PHP 7.4中的新功能(即将推出)

PHP 7.4是下一个PHP 7次要版本,预计将于2019年11月21日发布到General Availability。因此,现在是时候深入了解一些最令人兴奋的新增功能和新功能,这将使PHP更快,更可靠。

实际上,即使PHP 7.4能够显着提高性能并提高代码可读性,PHP 8也将成为PHP性能的真正里程碑,因为JIT包含的提议已经获得批准。

无论如何,今天我们正在经历PHP 7.4中我们期望的一些最有趣的功能和更改。因此,在您阅读本文之前,请务必保存以下日期:

你厌倦了缓慢的WordPress主机和可怕的支持吗?我们在Kinsta做不同的事情。查看我们的托管计划

  • 6月6日:PHP 7.4 Alpha 1
  • 7月18日:PHP 7.4 Beta 1 – 功能冻结
  • 11月21日:PHP 7.4 GA发布

您可以在官方RFC页面上查看功能和添加的完整列表。

PHP 7.4发布日期:

PHP 7.4计划于2019年11月21日发布。它是下一个PHP 7次要版本,应该可以显着提高性能并提高代码可读性。

使用PHP 7.4支持PHP的新功能?

在这篇文章中,我们将介绍应该添加到PHP 7.4最终版本的语言中的一些更改和功能:

  • 支持在数组内部解压缩 – 数组传播运算符(核心)
  • 箭头函数具有隐式按值范围绑定(Core)
  • Nulled Coalesce assign(?? =)运算符(Core)
  • 类型属性(核心)
  • 弱参考(核心)
  • 协变返回类型和逆变参数(核心)
  • 预加载(OPcache)
  • 新的自定义对象序列化机制(SPL)
  • 弃用

PHP 7.4是即将推出的PHP 7次要版本,它将使PHP更快,更可靠。 ?查看我们对新功能的深入了解!点击鸣叫

忘记array_merge:PHP 7.4在数组表达式中引入Spread运算符

自PHP 5.6起可用,参数解包是将数组和Traversable解包为参数列表的语法。要解压缩数组或Traversable,必须以…(3点)为前缀,如下例所示:

function test(… $ args){var_dump($ args); } test(1,2,3);

现在这个PHP 7.4 RFC建议将此功能扩展到数组定义:

$ arr =(… $ args);

扩展运算符在数组表达式中的第一个声明好处就是性能。实际上,RFC文档指出:

Spread运算符应该比array_merge具有更好的性能。这不仅是因为spread运算符是一种语言结构,而array_merge是一个函数,而且因为编译时优化可以用于常量数组。

Spread运算符的一个显着优点是它支持任何可遍历的对象,而array_merge函数仅支持数组。

以下是数组表达式中参数解包的示例:

$ parts =('apple','pear'); $ fruits =('banana','orange',… $ parts,'watermelon');后续代码var_dump($水果);

如果在PHP 7.3或更早版本中运行此代码,PHP会抛出一个Parse错误:

解析错误:语法错误,意外'…'(T_ELLIPSIS),在第3行的/app/spread-operator.php中期待')'

相反,PHP 7.4将返回一个数组:

array(5){(0)=> string(6)“banana”(1)=> string(6)“orange”(2)=> string(5)“apple”(3)=> string(4) “pear”(4)=> string(10)“watermelon”}

RFC声明我们可以多次扩展同一个数组。此外,我们可以在数组中的任何位置使用Spread Operator语法,因为可以在spread运算符之前或之后添加常规元素。因此,以下代码将按预期工作:

$ arr1 =(1,2,3); $ arr2 =(4,5,6); $ arr3 =(… $ arr1,… $ arr2); $ arr4 =(… $ arr1,… $ arr3,7,8,9);

也可以将函数返回的数组直接解包到新数组中:

function buildArray(){return('red','green','blue'); } $ arr1 =(… buildArray(),'pink','violet','yellow');

PHP 7.4输出以下数组:

array(6){(0)=> string(3)“red”(1)=> string(5)“green”(2)=> string(4)“blue”(3)=> string(4) “pink”(4)=> string(6)“violet”(5)=> string(6)“yellow”}

我们也可以使用生成器语法:

function generator(){for($ i = 3; $ i <= 5; $ i ++){yield $ i; $ arr1 =(0,1,2,… generator());

但我们不允许解压缩通过引用传递的数组。请考虑以下示例:

$ arr1 =('red','green','blue'); $ arr2 =(…&$ arr1);

如果我们尝试通过引用解压缩数组,PHP会抛出以下Parse错误:

解析错误:语法错误,第3行的/app/spread-operator.php中出现意外的'&'

无论如何,如果第一个数组的元素是通过引用存储的,那么它们也通过引用存储在第二个数组中。这是一个例子:

$ arr0 ='red'; $ arr1 =(&$ arr0,'green','blue'); $ arr2 =('white',… $ arr1,'black');

这是我们用PHP 7.4获得的:

array(5){(0)=> string(5)“white”(1)=>&string(3)“red”(2)=> string(5)“green”(3)=> string(4) “blue”(4)=> string(5)“black”}

Spread运营商提案以43比1的票数通过。

箭头功能2.0(短暂闭包)

在PHP中,匿名函数被认为是非常冗长且难以实现和维护。这个RFC建议引入更简单,更清晰的箭头函数(或简短闭包)语法,这样我们就可以大大清理PHP代码了。

请考虑以下示例:

function cube($ n){return($ n * $ n * $ n); } $ a =(1,2,3,4,5); $ b = array_map('cube',$ a);的print_r($ b)的

PHP 7.4允许使用更简洁的语法,上面的函数可以重写如下:

$ a =(1,2,3,4,5); $ b = array_map(fn($ n)=> $ n * $ n * $ n,$ a);的print_r($ b)的

目前,由于使用了语言结构,匿名函数(闭包)可以继承父作用域中定义的变量,如下所示:

$ factor = 10; $ calc = function($ num)use($ factor){return $ num * $ factor; };

但是在PHP 7.4中,父作用域中定义的变量由值隐式捕获(隐式按值作用域绑定)。所以我们可以将上面看到的整个函数写在一行上:

$ factor = 10; $ calc = fn($ num)=> $ num * $ factor;

父作用域中定义的变量可以在箭头函数中使用,就像我们使用use($ var)一样,并且不可能从父作用域修改变量。

新语法是对语言的一个很大改进,因为它允许我们构建更易读和可维护的代码。我们还可以使用参数和返回类型,默认值,可变长度参数列表(可变函数),我们可以通过引用传递和返回等。最后,短闭包也可以在类方法中使用,并且它们可以使用$ this变量就像常规闭包一样。

此RFC已获得51至8票的批准,因此我们可以预期它将成为PHP 7.4新增内容的一部分。

空融合分配运算符

添加PHP 7时,当我们需要将三元运算符与isset()结合使用时,coalesce运算符(??)会派上用场。它返回第一个操作数(如果存在且不为NULL)。否则,它返回第二个操作数。这是一个例子:

$ username = $ _GET('user')?? '没有人';

这段代码的作用非常简单:它获取请求参数并设置默认值(如果它不存在)。该行的含义是清楚的,但是如果我们在RFC的这个例子中有更长的变量名称呢?

$ this-> request-> data('comments')('user_id')= $ this-> request-> data('comments')('user_id')?? '值';

从长远来看,这段代码可能有点难以维护。因此,旨在帮助开发人员编写更直观的代码,此RFC建议引入空合并赋值运算符(?? =)。因此,我们可以编写以下代码,而不是编写前面的代码:

$ this-> request-> data('comments')('user_id')?? ='value';

如果left-hand参数的值为null,则使用右侧参数的值。
注意,虽然coalesce运算符是比较运算符,但?? =是赋值运算符。

该提案已获得37票对4票的批准。

键入的属性2.0

参数类型声明或类型提示允许指定预期传递给函数或类方法的变量的类型。类型提示是自PHP 5以来可用的功能,从PHP 7.2开始,我们可以将它们与对象数据类型一起使用。现在,PHP 7.4通过添加对第一类属性类型声明的支持,使类型提示向前迈出了一步。这是一个非常基本的例子:

class User {public int $ id; public string $ name; }

void和callable除外,支持所有类型:

public int $ scalarType; protected ClassName $ classType; private?ClassName $ nullableClassType;

RFC解释了不支持void和callable的原因:

不支持void类型,因为它没用,并且语义不清楚。

不支持可调用类型,因为其行为取决于上下文。

所以我们可以安全地使用bool,int,float,string,array,object,iterable,self,parent,任何类或接口名称,以及可空类型(?type)。

类型可用于静态属性:

public static iterable $ staticProp;

它们也允许使用var表示法:

var bool $ flag;

可以设置默认属性值,当然必须与声明的属性类型匹配,但只有可空属性可以具有默认的空值:

public string $ str =“foo”; public?string $ nullableStr = null;

相同的类型适用于单个声明中的所有属性:

public float $ x,$ y;

如果我们在属性类型上出错,会发生什么?请考虑以下代码:

class User {public int $ id; public string $ name; } $ user = new User; $ user-> id = 10; $ user-> name =();

在上面的代码中,我们声明了一个字符串属性类型,但我们将数组设置为属性值。在这种情况下,我们得到以下致命错误:

致命错误:未捕获TypeError:类型属性User :: $ name必须是字符串,数组在/app/types.php中使用:9

此RFC已获得70至1票的批准。

弱参考

通过此RFC,PHP 7.4引入了WeakReference类,它允许程序员保留对对象的引用,该对象不会阻止对象本身被破坏。

目前,PHP通过使用像pecl-weakref这样的扩展来支持弱引用。无论如何,新API与记录的WeakRef类不同。

以下是该提案的作者Nikita Popov的一个例子:

$ object = new stdClass; $ weakRef = WeakReference :: create($ object);后续代码var_dump($ weakRef->的get());未设置($对象);后续代码var_dump($ weakRef->的get());

第一个var_dump打印对象(stdClass)#1(0){},而第二个var_dump打印NULL,因为被引用的对象已被销毁。

此RFC以28票对5票通过。

协变返回和逆变参数

方差是类层次结构的一个属性,描述了类型构造函数的类型如何影响子类型。通常,类型构造函数可以是:

  • 不变量:如果超类型的类型约束子类型的类型。
  • 协变:如果保留类型的排序(类型从更具体到更通用的顺序排序)。
  • 逆变:如果它颠倒了顺序(类型从更通用到更具体的顺序排序)。

目前,PHP几乎没有参数和返回类型,只有少数例外。该RFC建议允许参数类型和返回类型的协方差和逆变,还提供了几个代码示例。

以下是协变返回类型的示例:

interface Factory {function make():object; class UserFactory实现Factory {function make():User; }

以下是逆变参数类型的示例:

interface Concatable {function concat(Iterator $ input); class Collection实现Concatable {//接受所有迭代,而不仅仅是Iterator函数concat(iterable $ input){/ *。 。 。 * /}}

有关PHP 7.4中协方差和逆变的详细信息,请参阅RFC。

这个RFC以39比1的票数通过。

预加载

德米特里·斯托戈夫的这个提议是我们最喜欢的,因为它应该会带来显着的性能提升。预加载是在模块初始化时将库和框架加载到OPCache中的过程(阅读有关PHP生命周期的更多信息)。

PHP生命周期

PHP生命周期(图片来源:PHP Internals)

以下是德米特里的预言:

在服务器启动时 – 在运行任何应用程序代码之前 – 我们可以将一组PHP文件加载到内存中 – 并使其内容“永久可用”到该服务器将服务的所有后续请求。这些文件中定义的所有函数和类将可用于开箱即用的请求,与内部实体完全相同。

这些文件在服务器启动时加载,在任何应用程序之前执行,并且可用于将来的任何请求。这在性能方面很棒。

预加载由特定的php.ini指令控制:opcache.preload。该指令指定在服务器启动时编译和执行的PHP脚本。此文件可用于预加载其他文件,包括它们或通过opcache_compile_file()函数(有关PHP文档的更多信息)。

但是有一个缺点。事实上,RFC明确指出:

预加载的文件永远保存在opcache内存中。如果没有其他服务器重新启动,修改其相应的源文件将不起任何作用。

但是,预加载文件中定义的所有函数将永久加载到PHP函数和类表中,并且可用于将来的每个请求。这将带来良好的性能改进,即使这些改进可能变化很大。

您可以在官方预加载RFC页面上阅读有关预加载的限制和例外的更多信息。

新的自定义对象序列化机制

这是Nikita Popov以大多数选票获得批准的另一项提案。

您的主人是否充分利用了最新技术?在Kinsta,我们使用针对WordPress优化的最佳技术堆栈。看看我们的计划

目前,我们有两种不同的机制来自定义PHP中的对象:

  • __sleep()和__wakeup()魔术方法
  • Serializable接口

根据Nikita的说法,这两个选项都存在导致代码复杂且不可靠的问题。您可以深入了解RFC中的这个主题。在这里我只提到新的序列化机制应该通过提供两个新的魔术方法__serialize()和__unserialize()来结合现有的两种机制来防止这些问题。

该提案以20票对7票获得通过。

弃用

PHP 7.4将弃用以下函数/功能。有关更全面的弃用列表,请查看PHP 7.4升级说明。

更改连接运算符的优先级

目前,在PHP中,“+”和“ – ”算术运算符和“。”字符串运算符是左关联的并且具有相同的优先级(阅读有关运算符优先级的更多信息)。

例如,请考虑以下行:

回声“总和:”。 $ a + $ b;

在PHP 7.3中,此代码生成以下警告:

警告:第4行的/app/types.php中遇到非数字值

这是因为连接是从左到右进行评估的。它与编写以下代码相同:

echo(“sum:”。$ a)+ $ b;

此RFC建议更改运算符的优先级,使“。”的优先级低于“+​​”和“ – ”运算符,以便在字符串连接之前始终执行加法和减法。该行代码应该等同于以下内容:

回声“总和:”。 ($ a + $ b);

这是一个两步提案:

  • 从版本7.4开始,当遇到带有“+”,“ – ”和“。”的未加表示的表达式时,PHP应发出弃用通知。
  • 应使用PHP 8添加这些运算符的实际优先级更改。

这两项提案都获得了大多数选票的批准。

弃用左关联三元运算符

在PHP中,三元运算符与许多其他语言不同,是左关联的。根据Nikita Popof的说法,对于在不同语言之间切换的程序员来说,这可能会让人感到困惑。

目前,在PHP中,以下代码是正确的:

$ b = $ a == 1? '一':$ a == 2? '两个':$ a == 3? '三':'其他';

它被解释为:

$ b =(($ a == 1?'one':$ a == 2)?'two':$ a == 3)? '三':'其他';

这可能会导致错误,因为它可能不是我们打算做的。因此,本RFC建议弃用并删除三元运算符的左关联性使用,并强制开发人员使用括号。

这是另一个两步建议:

  • 从PHP 7.4开始,没有明确使用括号的嵌套三元组将抛出弃用警告。
  • 从PHP 8.0开始,将出现编译运行时错误。

该提案已获得35票对10票的批准。

PHP 7.4对WordPress用户意味着什么?

PHP是Web上使用最广泛的服务器端编程语言。据W3Techs称,截至2019年5月28日,PHP的使用量仍在增长:

在我们所知道的服务器端编程语言的所有网站中,有79.0%使用PHP。

PHP版本

PHP使用情况(2019年5月)

不幸的是,使用已知服务器端编程语言的52.4%的网站仍然使用PHP 5。如果您添加仍使用PHP 7.0的用户数,则可以发现绝大多数网站都运行不受支持的PHP版本。

支持的PHP版本

支持的PHP版本(图像源:支持的版本)

根据官方的WordPress统计页面,截至撰写本文时,高达67%的所有WordPress网站都运行不受支持的PHP版本。只有3%多一点使用最新版本:PHP 7.3。您可以看到,超过31%的大多数用户仍在PHP 5.2上运行。

WordPress PHP版本

WordPress PHP版本(2019年5月)

我们强烈建议您向主机索取支持的PHP版本,最好根据WordPress的官方要求。截至撰写本文时,2019年5月,WordPress要求:

  • PHP 7.3或更高版本。
  • MySQL 5.6或更高版本或MariaDB版本10.1或更高版本。
  • HTTPS支持

PHP 7性能

从性能的角度来看,上面的数字尤其令人沮丧,因为PHP 7已经显示出明显更快。以下是一些统计数据:

  • 官方PHP基准测试表明,与PHP 5.6相比,PHP 7允许系统每秒执行两倍的请求,几乎是延迟的一半。
  • Christian Vigh还发布了一个PHP性能比较,他发现PHP 5.2比PHP 7慢400%。
  • Phoronix使用PHP 7.4 Alpha进行了一些早期基准测试,发现它比PHP 7.3略快。

我们使用PHP 7.3运行自己的PHP性能基准测试。我们看到,与PHP 5.6相比,PHP 7.3上的WordPress 5.0每秒执行的事务(请求)数量几乎是其三倍。我们即将发布PHP 7.4基准测试!

WordPress 5.0 PHP基准测试

WordPress 5.0 PHP基准测试

  • WordPress 5.0 PHP 5.6基准:91.64 req / sec
  • WordPress 5.0 PHP 7.0基准测试结果:206.71 req / sec
  • WordPress 5.0 PHP 7.1基准测试结果:210.98 req / sec
  • WordPress 5.0 PHP 7.2基准测试结果:229.18 req / sec
  • WordPress 5.0 PHP 7.3基准测试结果:253.20 req /sec?

由于测试新的所有第三方插件和主题以确保它们正常运行所涉及的时间很多,因此很多都很难更新。但很多时候,归结为他们还没有完成它。

检查您的PHP版本

不确定你正在运行什么版本的PHP?最简单的检查方法之一是使用Pingdom或Google Chrome Devtools等工具。第一个HTTP请求标头通常会显示版本。

检查Pingdom中的PHP版本

检查Pingdom中的PHP版本

这取决于主机不修改X-Powered-By标头值。但是,许多人出于安全原因(包括Kinsta)。如果是这样,您可能看不到您的PHP版本。在这种情况下,如果您运行的是WordPress 5.2或更高版本,则可以使用新的站点运行状况工具。转到“工具”→“站点健康”→“信息”,在“服务器”部分下,您将找到服务器的PHP版本。

使用WordPress站点运行状况工具检查PHP版本

使用WordPress站点运行状况工具检查PHP版本

或者,您可以安装免费插件,如版本信息,它将在您的WordPress管理仪表板的页脚中显示一些基本的服务器信息。查看PHP版本的其他几种方法包括通过FTP上传文件,或者只是联系主机并询问。

更新到PHP 7.4

PHP 7.4的最终版本还没有。但是,您可以在本地测试WordPress站点或在Docker等环境中检查脚本,这样您就可以从命令行测试不同版本的PHP。

一旦发布了PHP 7.4,您就可以利用Kinsta的临时环境,因为这将更像现场制作网站。在MyKinsta仪表板中通过几次简单的点击创建一个临时环境。

WordPress登台环境

WordPress登台环境

只需在“工具”下更改暂存站点的PHP引擎,即可开始测试以确保第三方插件和主题的兼容性。

改为PHP 7.3

改为PHP 7.3

我们将在正式发布一般可用性并由我们的开发人员进行全面测试后立即添加对PHP 7.4的支持。同时,您可能希望使用Docker等工具在计算机上运行PHP 7.4自己的测试。

在Docker上安装和运行PHP 7.4

幸运的是,您不需要手动编译和配置PHP 7.4。如果您已在系统上安装了Docker,则只需安装非官方的PHP-FPM 7.4 Docker Image,并在几秒钟内从命令行运行测试。

安装Nginx Docker镜像

安装Nginx Docker镜像

如果您更喜欢在浏览器中运行PHP 7.4代码,还需要安装Nginx或Apache映像。但不用担心。只需按照开发人员的指示操作即可。将Docker Image页面中的命令复制并粘贴到命令行工具中,您就可以开始使用了。

摘要

在这篇文章中,我们介绍了PHP 7.4发布后我们可以期待的大量更改和补充。如果您正在寻找完整的功能列表以及官方RFC文档,请查看以下资源:

  • PHP 7.4请求注释
  • PHP 7.4升级说明
  • PHP 7.4准备任务

我们将为您提供有关PHP 7.4及其发布的所有最新信息的最新信息。

你准备好测试即将推出的PHP功能吗?哪一个是你的最爱?在下面的评论中与我们分享您的想法。

相关文章