PHP8中有什么新功能?

2020-08-14 22:57:20

PHP8将于2020年11月26日发布。它是一个新的主要版本,这意味着它将引入一些突破性的变化,以及许多新的功能和性能改进。目前,PHP8处于功能冻结状态,这意味着不能再添加新功能。

由于这些突破性的更改,您更有可能需要对代码进行一些更改才能使其在PHP 8上运行。不过,如果您一直保持与最新版本保持同步,升级应该不会太困难,因为大多数突破性的更改在7.*版本中都已弃用。别担心,所有这些贬义都列在这篇帖子里了。

除了突破性的更改,PHP8还带来了一组不错的新特性,比如JIT编译器、联合类型、属性等。

考虑到PHP的动态类型特性,联合类型在很多情况下都很有用。联合类型是两个或多个类型的集合,这些类型指示可以使用这两个类型中的任何一个。

请注意,void永远不能是联合类型的一部分,因为它指示";根本没有返回值";。此外,可以使用|NULL或使用现有的?注释:

JIT-Just-In-Time编译器承诺显著提高性能,尽管并不总是在Web请求的上下文中。我已经在现实生活中的Web应用程序上做了自己的基准测试,似乎JIT在这些PHP项目上没有太大的不同(如果有的话)。

如果你想更多地了解JIT可以为PHP做些什么,你可以阅读我在这里写的另一篇文章。

如果您熟悉null合并操作符,那么您已经熟悉了它的缺点:它不能处理方法调用。相反,您需要中间检查,或者依赖某些框架提供的可选助手:

通过添加nullsafe操作符,我们现在可以在方法上具有类似于空合并的行为!

命名参数允许您通过指定值名称将值传递给函数,这样您就不必考虑它们的顺序,您还可以跳过可选参数!

函数(String$a,String$b,?字符串$c=NULL,?字符串$d=空){/*…。*/}foo(b:';value b';,a:';value a';,d:';value d';,);

属性(在其他语言中通常称为注释)提供了一种将元数据添加到类的方法,而不必解析文档块。

至于快速浏览,这里有一个来自RFC的属性示例:

使用\\;@@ExampleAttribute类{@@ExampleAttribute public const foo=';foo';;@@ExampleAttribute public$x;@@ExampleAttribute public function(@@ExampleAttribute$bar){}}。

请注意,此基本属性过去在原始RFC中称为PhpAttribute,但后来被另一个RFC更改。如果您想深入研究属性是如何工作的,以及如何构建您自己的属性;您可以在这个博客上深入阅读有关属性的内容。

您可以将其称为Switch表达式的老大哥:Match可以返回值,不需要Break语句,可以组合条件,使用严格的类型比较,并且不执行任何类型强制。

此RFC添加语法糖来创建值对象或数据传输对象。PHP现在可以将它们合并为一个,而不是为它们指定类属性和构造函数。

Class{public Currency$Currency;PUBLIC INT$Amount;PUBLIC函数(Currency$Currency,int$Amount,){$this->;Currency=$Currency;$this->;Amount=$Amount;}}。

有更多关于房地产促销的内容,你可以在这篇专门的帖子中读到。

虽然已经可以返回self,但静态直到PHP 8才是有效的返回类型。考虑到PHP的动态类型特性,它对许多开发人员都很有用。

有些人可能会说这是一种必要的邪恶:混合型导致许多人有复杂的情绪。不过,有一个非常好的理由来解释这一点:在PHP中,缺少类型可能意味着很多事情:

由于上述原因,增加了混合型是一件好事。MIXED本身表示以下类型之一:

请注意,Mixed还可以用作参数或属性类型,而不仅仅是返回类型。

还请注意,由于MIXED已包含NULL,因此不允许将其设置为可空。以下情况将触发错误:

//致命错误:混合类型不能为Null,Null已经是混合类型的一部分。函数():?{}。

此RFC将抛出从语句更改为表达式,这使得在许多新位置抛出异常成为可能:

以前,PHP用于对公共、受保护和私有方法应用相同的继承检查。换句话说:私有方法应该遵循与受保护方法和公共方法相同的方法签名规则。这没有意义,因为子类不能访问私有方法。

此RFC改变了这种行为,因此不再对私有方法执行这些继承检查。此外,使用最终的私有函数也没有意义,因此现在这样做将触发一个警告:

构建在PHP 7.4中添加的WeakRefs RFC的基础上,在PHP 8中添加了WeakMap实现。WeakMap保存对对象的引用,这不会阻止这些对象被垃圾收集。

以ORM为例,它们经常实现包含对实体类的引用的缓存,以提高实体之间关系的性能。这些实体对象不能被垃圾收集,只要该缓存有对它们的引用,即使缓存是唯一引用它们的东西。

如果该缓存层改为使用弱引用和映射,则PHP将在其他对象不再引用这些对象时对它们进行垃圾回收。特别是在ORM的情况下,它可以在一个请求中管理数百个(如果不是数千个)实体;弱映射可以提供一种更好、更资源友好的方式来处理这些对象。

类{私有WeakMap$cache;公共函数(对象$obj):{return$this->;cache[$obj]??=$this->;culteSomethingExpensive($obj);}}

一个小而有用的新特性:现在可以对对象使用::class,而不必对它们使用get_class()。它的工作方式与get_class()相同。

在PHP8之前,每当您想要捕获异常时,您都必须将其存储在一个变量中,而不管您是否使用该变量。对于非捕获捕获,您可以省略该变量,因此不是这样:

请注意,要求始终指定类型,您不能有一个空的捕获。如果要捕获所有异常和错误,可以使用Throwable作为捕获类型。

在调用函数时已经可以了,参数列表中仍然缺少尾随逗号支持。PHP 8现在允许这样做,这意味着您可以执行以下操作:

作为附注:闭包的使用列表中也支持尾随逗号,这是一个疏忽,现在通过单独的RFC添加。

您已经可以使用DateTime::createFromImmutable($immutableDateTime)从DateTimeImmutable对象创建一个DateTime对象,但是反过来很棘手。通过添加DateTime::createFromInterface()和DatetimeImmutable::createFromInterface(),现在有了一种将DateTime和DateTimeImmutable对象相互转换的通用方法。

Stringable接口可用于键入提示任何字符串或实现__toString()。此外,每当类实现__toString()时,它都会自动在幕后实现接口,不需要手动实现它。

类{PUBLIC Function():{Return';foo&39;;}}Function(Stringable$Stringable){/*…。*/}bar(new foo());bar(';abc';);

有些人可能会说这是早就应该做的,但是我们最终不必再依赖strpos()来知道一个字符串是否包含另一个字符串。

新的fdiv()函数的作用类似于fmod()和intdiv()函数,它们允许被0除以。根据具体情况,您将得到INF、-INF或NaN,而不是错误。

GET_DEBUG_TYPE()返回变量的类型。听起来像是gettype()可以做的事情吗?Get_debug_type()为数组、字符串、匿名类和对象返回更有用的输出。

例如,在类\foo\Bar上调用gettype()将返回Object。使用GET_DEBUG_TYPE()将返回类名。

可以在RFC中找到GET_DEBUG_TYPE()和gettype()之间差异的完整列表。

资源是PHP中的特殊变量,指的是外部资源。一个例子是MySQL连接,另一个是文件句柄。

这些资源中的每一个都会被分配一个ID,尽管以前知道该ID的唯一方法是将资源强制转换为int:

特征可以指定必须由使用它们的类实现的抽象方法。不过,有一个警告:在PHP8之前,这些方法实现的签名没有经过验证。以下内容有效:

特性测试{抽象公共函数(int$input):;}class{use;public function($input){return$input;}}。

在使用特征并实现其抽象方法时,PHP8将执行正确的方法签名验证。这意味着您需要改写以下内容:

函数的作用是:返回值的数组。此RFC使用PhpToken::getall()方法添加一个PhpToken类。此实现使用对象,而不是普通值。它消耗更少的内存,更容易阅读。

从RFC:";统一变量语法RFC解决了PHP变量语法中的许多不一致问题。这个RFC打算解决一小部分被忽视的案例。

很多人都参与到为所有内部函数添加适当类型注释的工作中。这是一个长期存在的问题,通过在以前版本中对PHP所做的所有更改,最终可以解决这个问题。这意味着内部函数和方法在反射中将具有完整的类型信息。

以前,在没有启用JSON扩展的情况下编译PHP是可能的,现在这是不可能的了。由于JSON被如此广泛地使用,所以它最优秀的开发人员可以一直依赖于它的存在,而不是必须确保扩展首先存在。

正如前面提到的:这是一个重大更新,因此会有突破性的变化。最好的做法是在升级文档中查看中断更改的完整列表。

不过,许多这些突破性的更改在以前的7.*版本中都已被弃用,所以如果您多年来一直保持最新状态,那么升级到PHP 8应该不会那么困难。

PHP中的用户定义函数已经抛出TypeError,但内部函数没有抛出,而是发出警告并返回NULL。从PHP8开始,内部函数的行为已经保持一致。

许多以前只触发警告或通知的错误已转换为适当的错误。以下警告已更改。

无法将元素添加到数组,因为下一个元素已被占用:错误异常而不是警告。

此更改可能会显示在PHP8之前隐藏的错误。请确保在生产服务器上设置DISPLAY_ERROR=OFF!

它现在是E_ALL,而不是除E_NOTICE和E_DEVERATED之外的所有内容。这意味着可能会弹出许多以前被悄悄忽略的错误,尽管在PHP8之前可能已经存在。

来自RFC:PDO的当前默认错误模式为静默。这意味着当发生SQL错误时,除非开发人员实现自己的显式错误处理,否则不会发出任何错误或警告,也不会引发任何异常。

虽然在PHP7.4中已不推荐使用,但此更改现在生效。如果你要写这样的话:

在PHP8之前,可以对数组、资源或对象应用算术运算符或按位运算符。这是不可能的,并且将抛出一个TypeError:

PHP用于将名称空间的每个部分(用反斜杠\分隔)解释为标记序列。此RFC改变了这一行为,这意味着保留名称现在可以在名称空间中使用。

PHP的类型系统在遇到字符串中的数字时会尝试做很多聪明的事情。这个RFC使这种行为更加一致和清晰。

此RFC修复了PHP中非常奇怪的情况,即0=#34;foo&34;结果为true。还有其他一些类似的边缘情况,这个RFC修复了它们。

升级指南指定,如果您扩展了这些类,并且仍然希望同时支持PHP 7和PHP 8,则允许以下签名:

在PHP8之前,排序算法是不稳定的。这意味着不能保证相等元素的顺序。PHP8将所有排序函数的行为更改为稳定排序。

来自RFC:不兼容的方法签名导致的继承错误当前抛出致命错误或警告,具体取决于错误原因和继承层次结构。

在PHP7.*开发过程中,添加了几个弃用项,现在已在PHP8中完成。