Categories
程式開發

PHP 7入门:新特性简介


本文要点

  • PHP 7是人们期待已久的、PHP 5的后继版本。 PHP 7.4是PHP 7的最后一个小版本。
  • 除提供了多项新特性外,PHP 7.x速度更快,而且已经云就绪。
  • PHP 7.2部分支持协变和逆变,PHP 7.4实现了完全支持。
  • PHP 7.2新增了类型object
  • PHP仍然是Web上最常见的语言之一。在服务端编程语言已知的网站中,78.6%的使用了PHP

PHP快成为一种被遗忘的语言了,自2004年PHP 5.0发布之后,十多年没有一个新的大版本。更糟糕的是,PHP 6.x被放弃是因为计划向PHP添加原生Unicode支持却无法实现。

PHP 7.0是一个大版本,增加了一些改进和新特性。7.0中有一些比较显著的新特性,包括:字符串、整数、浮点数和布尔值的标量类型声明;返回类型声明;用于数组常量的新函数define() ;匿名类。该版本还添加了一些特性来改进Unicode支持,包括IntlChar类和Unicode代码点转义语法。

此外,PHP 7还添加了增强assert()函数的期望(expectations ),而生成器返回函数和生成器委托改进了生成器的功能。随后的小版本,从PHP 7.1到PHP 7.4,还增加了其他新特性。

在本系列文章中,我们将讨论PHP 7.x版本中的各种新特性。但首先,让我们探讨一下为什么使用PHP 7。

为什么使用PHP 7?

简单来说,PHP 7让PHP达到了其他现代语言的水平。

下面是使用PHP 7其中一些最重要的原因:

  1. 在所有的网站中,有36.4%使用WordPress。PHP 7是WordPress官方推荐的PHP版本。

当更新PHP的版本时,WordPress建议更新到推荐的PHP 7.3版本。PHP内部团队做得很棒,他们让最新版本成为PHP迄今为止最快的版本。这意味着更新将提高你网站的速度,对你和你的访问者而言都是如此。

  1. PHP 7提供了前面提到的多项新特性。

  2. PHP 7基于一个新引擎Zend Engine,性能更好,速度更快。Zend非常快,这一点从几个在不同平台/配置下运行的速度基准测试中可以看出来。

  3. PHP 7使用了高效的数据结构,使其比之前的版本更简洁。

  4. PHP 7已经云就绪,大部分主流云服务提供商的LAMP Stack都支持它。

环境设置

要测试或运行本文提供的示例脚本,请下载并安装PHP 7的最新版本(PHP 7.4)。平台不同,下载的二进制文件和安装步骤也会有些差异,因此,请参阅官方PHP文档。不要忘记将安装根目录,例如C:PHP7.4php-7.4-ts-windows-vc15-x64-r6c9821a添加到PATH 环境变量中。将php.ini-productionphp.ini-development重命名为php.ini。要使用/ext目录中的扩展,请在php.ini中设置extension_dir指令:

extension_dir = "./ext"

使用下面的命令启动内置服务器:

php -S localhost:8000

在根目录(即安装目录,例如,C:PHP7php-7.3.0-Win32-VC15-x64)的scripts子目录中添加要运行的所有脚本。可以使用php.ini中的doc_root指令将根目录设置为不同的路径。要重用本示例中的PHP脚本,请单独保存它们,而不是将每个脚本作为test.php测试/运行。

协变和逆变

PHP 7.2引入了有限协变和逆变。协变是指子类的方法能够返回更具体的返回类型。逆变是指子类的方法接受不那么具体的参数类型。更具体/不那么具体是在超/子类的上下文中定义的,子类是更具体的。一个类扩展另一个类可以重写其方法,同时仍然保持逆变(对于参数类型)和协变(对于返回类型)。

PHP 7.2仅提供对协变和逆变的有限支持,这意味着只支持没有提供类型的情况。具体来说,可以在重写超类中不存在返回类型的函数时定义返回类型,而在重写超类中存在参数的函数时省略参数类型。

例如,创建一个脚本,声明一个只有一个函数fn1的类A,创建另一个类B,继承类A并重写其fn1 函数。

在重写后的函数fn1中,参数类型被删除了,默认成了mixed类型,该参数类型比类A中的类型B更宽泛。在重写后的方法中删除参数类型,而不管类是否是抽象的,这是PHP 7的另一项新特性。

重写后的fn1方法返回类型是A,其范围要比类A中的mixed类型窄。以下是代码:

新对象类型

PHP 7.2新增了一个类型object,该类型可以用作参数类型和返回类型。所有类类型的实例都是对象。为了演示如何使用object作为参数类型和返回类型,在文档根目录下的scripts目录中创建一个脚本object.php,并声明两个类ClassAClassB,每个类都定义 一个hello()函数,该函数回显字符串消息。接下来,向脚本本身添加hello()函数,参数类型和返回类型都是object。直接在脚本中添加的hello()函数返回类ClassB的一个实例:

function hello(object $obj) : object
{
return new ClassB();
}

使用ClassA类的实例作为参数调用该函数,并在返回的对象上调用hello()函数。

hello(new ClassA())->hello();
The object.php is listed:
hello();
?>

使用URL http://localhost:8000/scripts/object.php运行脚本,输出如下:
Hello from ClassB

由于这是我们运行的第一个示例脚本,所以我们把它在浏览器中的输出截了图,如下所示:

PHP 7入门:新特性简介 1

图1:object.php的输出

object类型本身并不代表一个类;它只是一个类型。如果object之外的任何类型转化为objec,就会创建内置类stdClass的一个实例。

数组可以强制转换为对象类型object,生成的对象具有名称类似数组键的属性。为了演示如何将数组转换为对象以及几项有用的相关任务,请创建object_array.php脚本并通过强制转换为object来声明对象。

$obj = (object) array('journal' => 'Oracle Magazine', 'publisher' => 'Oracle Publishing','edition' => 'January February 2018');

现在,可以使用命名键来输出对象属性了。

echo $obj->{'journal'};
echo $obj->{'publisher'};
echo $obj->{'edition'};

bool isset (mixed$var [,mixed$... ])函数可以用于检查属性是否已经像下面这样设置:
var_dump(isset($obj->{'journal'}));

使用mixedkey ( array $array)函数输出一个对象键。

var_dump(key($obj));

使用mixed next ( array &$array)前移内部数组指针。

next($obj);

调用issetkey函数获取下一个数组元素。按顺序重复调用nextissetkey函数获取下一个元素。可以直接访问对象成员变量来输出它们的值。

echo $obj->journal; 
echo $obj->publisher;
echo $obj->edition; 

检查从数组转换而来的对象是否是stdClass的实例。

if($obj instanceof stdClass){
echo '$obj is instance of built-in class stdClass';
}

字符串可以强制转换为object。转换后的对象的值可以使用成员变量scalar访问。检查转换后的对象是否为stdClass的实例。

$obj = (object) 'hello';
echo $obj->scalar;
if($obj instanceof stdClass){
echo '$obj is instance of built-in class stdClass';
}

以下是object_array.php脚本的内容:

 'Oracle Magazine', 'publisher' => 'Oracle Publishing','edition' => 'January February 2018');
echo $obj->{'journal'};
echo "
"; echo $obj->{'publisher'}; echo "
"; echo $obj->{'edition'}; echo "
"; var_dump(isset($obj->{'journal'})); echo "
"; var_dump(key($obj)); next($obj); echo "
"; var_dump(isset($obj->{'publisher'})); echo "
"; var_dump(key($obj)); next($obj); echo "
"; var_dump(isset($obj->{'edition'})); echo "
"; var_dump(key($obj)); echo "
"; echo $obj->journal; echo "
"; echo $obj->publisher; echo "
"; echo $obj->edition; echo "
"; if($obj instanceof stdClass){ echo '$obj is instance of built-in class stdClass'; echo "
"; } $obj = (object) 'hello'; echo $obj->scalar; echo "
"; if($obj instanceof stdClass){ echo '$obj is instance of built-in class stdClass'; } ?>

运行该脚本会输出以下内容:

Oracle Magazine
Oracle Publishing
January February 2018
bool(true)
string(7) "journal"
bool(true)
string(9) "publisher"
bool(true)
string(7) "edition"
Oracle Magazine
Oracle Publishing
January February 2018
$obj is instance of built-in class stdClass
hello
$obj is instance of built-in class stdClass

不仅可以将数组和字符串转换为对象,还可以将任何类型的值转换为对象,包括intfloatbool。例如,将int转换为object,输出其scalar值,然后用接下来的脚本检查转换后的对象是否为stdClass的实例:

scalar;
echo "
"; if($obj instanceof stdClass){ echo '$obj is instance of built-in class StdClass'; }?>

输出如下:
1

$obj is instance of built-in class stdClass

类的实例是对象而不是stdClass的实例,将它们转换为object不会使它们成为stdClass的实例。为了演示这一点,我们创建一个名为object_instance_of.php的脚本。然后声明一个类并实例化它。下面的脚本将展示如何确定一个类的实例是否是stdClass的实例;接下来,该脚本会将类的实例强制转换为object,并确定转换后的对象是否是stdClass的实例。object_instance_of.php脚本如下所示:

';
if ($A instanceof stdClass) {
echo '$A is instance of built-in class stdClass'; }
else{
echo '$A is not instance of built-in class stdClass';
}
echo '
'; echo '
'; $AObj = (object)$A; if ($AObj instanceof stdClass) { echo '$AObj is instance of built-in class stdClass'; }else{ echo '$AObj is not instance of built-in class stdClass'; } echo '
'; ?>

以下是该脚本的输出:

$A is not instance of built-in class stdClass
$AObj is not instance of built-in class stdClass

命名类或匿名类的实例已经是object,将其强制转换为object不会改变其类型。空数组和NULL值也可以转换为object。如前所述,stdClass是默认的PHP对象,当将标量、数组和NULL强制转换为object时,将创建stdClass的一个实例。匿名类object、从空数组创建的object、从NULL创建的object或没有函数或变量的类都不会被认为是空的,将empty()应用于它们中的任何一个都不会返回TRUEempty()函数的作用是:仅当变量或对象不存在或它的值为FALSE时才返回TRUE
如果你想测试一下,可以创建一个脚本文件object_empty.php,并将下面的代码粘贴进去:

";
var_dump($obj1);
echo "
"; var_dump($obj2); echo "
"; echo empty ($obj1); echo "
"; $obj1=NULL; $obj3=(object)$obj1;// NULL转换为对象 var_dump($obj3); echo "
"; echo empty ($A); echo "
"; echo empty ($obj2); echo "
"; echo empty ($obj3); ?>

该脚本创建了每一种匿名类的对象:从空数组创建的对象,从NULL创建的对象,以及没有函数或变量的类对象。运行该脚本将生成以下输出。

object(A)#3 (0) { } 
object([email protected])#1 (0) { } 
object(stdClass)#2 (0) { };
object(stdClass)#1 (0) { } 

object类型可以用于参数类型的逆变(放宽)和返回类型的协变(缩窄)。

完全协变和逆变

我们已经讨论了PHP 7.2对有限协变的支持,它支持向扩展类中的方法添加返回类型,即使在超类中没有声明任何返回类型。我们还讨论了对有限逆变的支持,它允许在扩展类中不指定方法参数的类型。

PHP 7.4添加了对协变和逆变的完全支持。完全支持允许开发人员使用不那具体的参数类型和更具体的返回类型,这意味着参数类型可以用它的超类型替换,而返回类型可以用子类型替换。回想一下,PHP 7.2中对协变和逆变的支持仅限于无类型。在下面的脚本中,ClassB继承了ClassAClassD继承了ClassC。与ClassC相比,ClassD中的函数fn1声明了一个不那么具体的参数类型和一个更具体的返回类型。


以下是全变型支持的部分特性:

  • 只有在使用自动加载时,才能提供全变型支持;
  • 支持object类型变型;
  • 不支持callable类型变型;
  • 引用参数仍然是逆变的,引用返回类型仍然是协变的;
  • 变型验证是在最后一个连续类型(consecutive type)声明后才进行。

在本系列的下一篇文章中,我们将讨论PHP 7.x中类和接口的新特性。

作者简介:

Deepak Vohra是Sun认证Java程序员和Web组件开发人员。他一直在WebLogic Developer’s Journal、XML Journal、ONJava、java.net、IBM developerWorks、Java Developer’s Journal、Oracle Magazine和devx上发表与Java和Java EE相关的技术文章。Deepak还是一名Docker导师,已出版了五本关于Docker的著作。Deepak还发表了多篇关于PHP的文章,并出版了一本著作Ruby on Rails for PHP and Java Developers

原文链接:

PHP 7 — Getting Started and OOP Improvements