PHP 7入门:新特性简介

2020 年 6 月 19 日

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.4\php-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:\PHP7\php-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类型窄。以下是代码:


<?phpclass A {  function fn1(B $b) {} }class B extends A {  function fn1($b): A{} }
复制代码


新对象类型


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:<?phpClass ClassA{function hello(){  echo "Hello from ClassA";}}class ClassB{function hello(){   echo "Hello from ClassB";}} function hello(object $obj) : object{  return new ClassB();}hello(new ClassA())->hello();?>
复制代码


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


Hello from ClassB


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



图 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脚本的内容:


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


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


Oracle MagazineOracle PublishingJanuary February 2018bool(true)string(7) "journal"bool(true)string(9) "publisher"bool(true)string(7) "edition"Oracle MagazineOracle PublishingJanuary February 2018$obj is instance of built-in class stdClasshello$obj is instance of built-in class stdClass
复制代码


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


<?php$obj = (object) 1;echo $obj->scalar;echo "<br/>";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脚本如下所示:


<?phpClass A{}$A = new A;echo '<br/>';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 '<br/>';echo '<br/>';$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 '<br/>'; ?>
复制代码


以下是该脚本的输出:


$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,并将下面的代码粘贴进去:


<?php$obj1 = (object)(new class{}); // 实例化匿名类$obj2 = (object)[]; // 将空数组转换为对象class A{}$A=new A();  // 空类的实例var_dump($A);echo "<br/>";var_dump($obj1);echo "<br/>";var_dump($obj2);echo "<br/>"; echo empty ($obj1);echo "<br/>";$obj1=NULL;$obj3=(object)$obj1;// NULL转换为对象var_dump($obj3); echo "<br/>";echo empty ($A);echo "<br/>";echo empty ($obj2);echo "<br/>";echo empty ($obj3);?>
复制代码


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


object(A)#3 (0) { } object(class@anonymous)#1 (0) { } object(stdClass)#2 (0) { };object(stdClass)#1 (0) { } 
复制代码


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


<?phpclass A{public function fn(object $obj)  {}}class B extends A{public function fn($obj) : object {} } 
复制代码


完全协变和逆变


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


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


<?phpclass ClassA {}class ClassB extends ClassA {}class ClassC {    public function fn1(ClassB $b): ClassA {}}class ClassD extends ClassC {    public function fn1(ClassA $a): ClassB {}}?>
复制代码


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


  • 只有在使用自动加载时,才能提供全变型支持;

  • 支持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


2020 年 6 月 19 日 15:241622

评论 1 条评论

发布
用户头像
一看前面两段,就知道不是PHPer写的,扫一眼到最后,过来是Oracle派来黑PHP的
2020 年 06 月 22 日 09:10
回复
没有更多评论了
发现更多内容

如何从危机中提炼总结,做好2020年的复盘?

CECBC区块链专委会

复盘 经济

拼多多五面面经(Java岗),全面涵盖Java基础到高并发级别

Java成神之路

Java 程序员 架构 面试 编程语言

盘点 2020 |协作,是另外一种常态

Winfield

领域驱动设计 DDD 协作 远程协作 盘点2020

【得物技术】如何测试概率性事件-二项分布置信区间

得物技术

测试 开发 概率 得物 得物技术

华为全栈AI技术干货深度解析,解锁企业AI开发“秘籍”

华为云开发者社区

AI 全栈 开发

为什么要在以太坊上构建去中心化缓存层?到底要怎样做呢?

CECBC区块链专委会

以太坊

LeetCode题解:42. 接雨水,动态规划,JavaScript,详细注释

Lee Chen

算法 LeetCode 前端进阶训练营

美团五面+滴滴四面,复盘总结117道面试题,大厂套路展露无遗

Java架构之路

Java 程序员 架构 面试 编程语言

小程序市场的「App Store」来了!你准备好吃“螃蟹”了吗?

蚂蚁集团移动开发平台 mPaaS

小程序生态 mPaaS appstore

Locust快速上手指南

行者AI

接口自动化传值处理

行者AI

得物App亮相QCon全球软件开发大会,分享百倍增长背后的技术力量

得物技术

效率 技术 得物 得物技术 Qcon

普本开发三年,每天两小时面试备战,2个月后五面阿里定级P7

Java架构之路

Java 程序员 架构 面试 编程语言

高光时刻!美团推出Spring源码进阶宝典:脑图+视频+文档

996小迁

spring 源码 架构 笔记

接口自动化测试的实现

行者AI

Rust太难?那是你没看到这套Rust语言学习万字指南!

华为云开发者社区

rust 语言 开发语言

资深码农:拿下软件测试,只需掌握好这两种方法!

华为云开发者社区

软件 工具 测试

AOFEX交易所APP系统开发|AOFEX交易所软件开发

开發I852946OIIO

系统开发

XDAG技术详解1

老五

浅谈 WebRTC 的 Audio 在进入 Encoder 之前的处理流程

阿里云视频云

WebRTC 音频技术 音视频算法 音频

3面抖音犹如开挂,一周直接拿下offer,全靠这份啃了两个月「Java进阶手册」+[Java面试宝典]

云流

编程 程序员 计算机 java面试

腾讯五面、快手三面已拿offer(Java岗位),分享个人面经

Java成神之路

Java 程序员 架构 面试 编程语言

软件测试中需要使用的工具

测试人生路

软件测试

15天成功拿到阿里offer 我是如何逆袭成功?全靠“Java程序员面试笔试通关宝典”真够可以!

比伯

Java 编程 架构 面试 程序人生

5年Java高工经验,我是如何成功拿下滴滴D7Offer的?

Java架构追梦

Java 学习 架构 面试 滴滴

双循环背景下的全球供应链机遇与挑战

CECBC区块链专委会

供应链物流

jenkins实现接口自动化持续集成(python+pytest+ Allure+git)

行者AI

半个多月时间4面阿里,已经成功拿下offer,分享一下个人面经

Java成神之路

Java 程序员 架构 面试 编程语言

阿里三面,复盘总结55题:java基础+分布式+网络+架构设计

Java成神之路

Java 程序员 架构 面试 编程语言

《迅雷链精品课》第十三课:PBFT算法

迅雷链

区块链

自定义TBE算子入门,不妨从单算子开发开始

华为云开发者社区

算法 算子 自定义

PHP 7入门:新特性简介-InfoQ