您好,欢迎访问一九零五行业门户网

PHP 8 中新特性以及重大调整

php 8,php 的一个新的大版本,预计将于2020年12月3日发布,这意味着将不会有 php 7.5 版本。php8目前正处于非常活跃的开发阶段,所以在接下来的几个月里,情况可能会发生很大的变化。
在这篇文章中,我会维持一个最新的清单列表,列出预计会出现的新特性、性能提升和突破性的变化。由于 php 8 是一个新的大版本,因此您的代码被破坏的可能性更高。如果您始终保持运行 php 的最新版本,那么升级相对来说就会轻松很多,因为在7. *版本中,大多数重大更改均已弃用。
除重大更改外,php 8还带来了一些不错的新功能,比如说 jit编译器, 联合类型, 属性,以及更多。
新特性从新特性开始,请记住 php8 仍处于活动开发阶段,因此此列表将随着时间的推移而增长。
联合类型考虑到 php 动态语言类型的特性,现在很多情况下,联合类型都是很有用的。联合类型是两个或者多个类型的集合,表示可以使用其中任何一个类型。
public function foo(foo|bar $input): int|float;
请注意,联合类型中不包含 void,因为void 表示的含义是“根本没有返回值”。  另外,可以使用 |null 或者现有的 ? 表示法来表示包含 nullable 的联合体 :
public function foo(foo|null $foo): void;public function bar(?bar $bar): void;
jitjit — just in time — 编译器虽然不总是在 web 请求的上下文中,但是有望显着地提高性能。目前还没有完成任何准确的基准测试,但是肯定会到来。
如果您想进一步了解jit对php的作用,可以阅读我写过的另一篇文章此处。
属性属性在其他语言中通常被称为 注解 ,提供一种在无需解析文档块的情况下将元数据添加到类中的方法。
快速浏览一下,这里有一份来自 rfc 的属性示例:
use app\attributes\exampleattribute;<<exampleattribute>>class foo{    <<exampleattribute>>    public const foo = 'foo';    <<exampleattribute>>    public $x;    <<exampleattribute>>    public function foo(<<exampleattribute>> $bar) { }}
<<phpattribute>>class exampleattribute{    public $value;    public function __construct($value)    {        $this->value = $value;    }}
如果您想深入了解属性如何工作以及如何构建自己的属性,您可以在此博客上阅读有关深入属性的信息。
新增 static 返回类型尽管已经可以返回 self,但是 static 直到 php 8 才是有效的返回类型 。考虑到 php 具有动态类型的性质,此功能对于许多开发人员将非常有用。
class foo{    public function test(): static    {        return new static();    }}
新增 mixed 类型有人可能将其称为必要的邪恶:mixed 类型让许多人感觉十分混乱。然而,有一个很好的论据支持去实现它:缺少类型在 php 中会导致很多情况:
函数不返回任何内容或返回空值
我们需要多种类型的一种类型
我们需要的是php中不能进行类型提示的类型
因为上述原因,添加 mixed 类型是一件很棒的事儿。mixed 本身代表下列类型中的任一类型:
array
bool
callable
int
float
null
object
resource
string
请注意,mixed  不仅仅可以用来作为返回类型,还可以用作参数和属性类型。
另外,还需要注意,因为 mixed  类型已经包括了 null,因此 mixed  类型不可为空。下面的代码会触发致命错误:
// 致命错误:混合类型不能为空,null已经是混合类型的一部分。function bar(): ?mixed {}
throw 表达式该rfc将throw从一个语句更改为一个表达式,这使得可以在很多新地方抛出异常:
$triggererror = fn () => throw new myerror();$foo = $bar['offset']  throw new offsetdoesnotexist('offset');
弱映射基于在 php 7.4 中新增的 弱引用 rfc,php 8 中新增了 weakmaps(弱映射)的实现。 weakmaps(弱映射)在保持对一些对象的引用的同时,并不会组织这些对象被垃圾回收机制处理 。
以orm为例,它们通常实现保存对实体类的引用的缓存,从而提高实体类之间关联的性能。 只要缓存中存在对这些实体类的引用,那么这些类就无法被垃圾回收机制回收,尽管除了缓存中,已经没有别处再引用这些实体类,它们依然不会被垃圾处理机制处理。
如果这个缓存层使用了弱引用和弱映射,那么 php 将会在这些实体类没有任何其他引用时,对其进行垃圾回收。 尤其是对于 orms,它可以管理一个请求中的数百个(如果不是数千个)实体;弱映射可以提供一种更好的、对资源更友好的方式来处理这些对象。
下面是弱映射基本的例子,摘抄自 rfc :
class foo {    private weakmap $cache;    public function getsomethingwithcaching(object $obj): object    {        return $this->cache[$obj]           = $this->computesomethingexpensive($obj);    }}
允许对对象使用 ::class一个很小但是很有用的新特性:现在可以在对象上使用 :: class ,而不必在对象上使用 get_class() ,它的工作方式跟 get_class() 相同。
$foo = new foo();var_dump($foo::class);
non-capturing catches在php 8 之前,无论何时你想要捕获一个异常,你都需要先将其存储到一个变量中,不管这个变量你是否会用到。通过 non-capturing catches 你可以忽略变量,所以替换下面的代码:
try {    // something goes wrong} catch (myspecialexception $exception) {    log::error(something went wrong);}
你现在可以这么做:
try {    // something goes wrong} catch (myspecialexception) {    log::error(something went wrong);}
请注意,必须始终指定类型,不允许将 catch 留空,如果你想要捕获所有类型的异常和错误,需要使用  throwable 作为捕获类型。
参数列表中的尾部逗号当调用函数时已经支持尾部逗号,但是参数列表中仍然缺少尾随逗号支持。现在php8中允许这样做,这意味着您可以执行以下操作:
public function(    string $parametera,    int $parameterb,    foo $objectfoo,) {    // …}
从接口创建datetime 对象你已经可以使用 datetime::createfromimmutable($immutabledatetime) 从  datetimeimmutable 对象创建一个 datetime 对象, 而另一种方法则更加取巧。通过添加datetime::createfrominterface()和datetimeimmutable::createfrominterface()现在有一种通用的方法可以将datetime和datetimeimmutable对象相互转换。
datetime::createfrominterface(datetimeinterface $other);datetimeimmutable::createfrominterface(datetimeinterface $other);
新增 stringable接口stringable接口可用于键入提示任何字符串或实现__ tostring()的内容。此外,每当一个类实现__ tostring()时,它就会自动实现后台接口,而无需手动实现。
class foo{    public function __tostring(): string    {        return 'foo';    }}function bar(stringable $stringable) { /* … */ }bar(new foo());bar('abc');
新增 str_contains() 函数 rfc有些人可能会说这是早该发生的,但我们最终不必再依赖strpos来知道一个字符串是否包含另一个字符串。
无需这样做:
if (strpos('string with lots of words', 'words') !== false) { /* … */ }
你可以这样做:
if (str_contains('string with lots of words', 'words')) { /* … */ }
新增 str_starts_with() 和 str_ends_with() 函数这是另外两个早该出现的函数,现在已在核心函数中添加了这两个函数。
str_starts_with('haystack', 'hay'); // truestr_ends_with('haystack', 'stack'); // true
新增 fp() 函数新的fp()函数的作用类似于fmod()和intp()函数,它们可以除以0。视情况而定,将得到inf,-inf或nan。
新增 get_debug_type() 函数get_debug_type()返回变量的类型,听起来好像跟 gettype() 的作用一样啊?get_debug_type()  可以为数组,字符串,匿名类和对象返回更有用的输出信息。
例如,在类\ foo \ bar上调用gettype()将返回object,而使用get_debug_type()将返回类名。
如下表:
valueget_debug_type()gettype()
0 int integer
0.1 float double
true bool boolean
false bool boolean
“hello” string
[] array
null null null
a class with name “foo\bar” foo\bar object
an anonymous class class@anonymous object
a resource resource (xxx) resource
a closed resource resource (closed)
可以在rfc中找到get_debug_type()和gettype()之间的差异的完整列表。
新增 get_resource_id() 函数资源是php中的特殊变量,指的是外部资源。一个示例是mysql连接,另一个是文件句柄。
这些资源中的每一个都分配有一个id,然而在这之前,如果想获取某资源的id,唯一方法是将资源转换为int:
$resourceid = (int) $resource;
php 8添加了get_resource_id()函数,使此操作更加明显且类型安全:
$resourceid = get_resource_id($resource);
traits 改进中的抽象方法traits  可以指定必须由使用它们的类所实现的抽象方法。需要注意的是: 在 php 8 之前,尚未验证这些方法已经实现的标识。以下内容有效:
trait test {    abstract public function test(int $input): int;}class usestrait{    use test;    public function test($input)    {        return $input;    }}
当使用 traits 并实现其抽象方法时,php 8将执行适当的方法进行标识验证抽象方法是否确实被实现。这意味着您需要编写以下代码:
class usestrait{    use test;    public function test(int $input): int    {        return $input;    }}
token_get_all() rfc的对象实现token_get_all()函数返回一个值数组,该rfc使用phptoken :: getall()方法新增了phptoken类。此实现适用于对象而不是普通值。它消耗更少的内存,并且更易于阅读。
可变语法调整 在rfc中:“统一变量语法rfc解决了php变量语法中的许多不一致之处。该rfc旨在解决一小部分被忽略的情况。”
内部函数的类型注解许多人 投入 了为所有内部函数添加适当的类型注释的工作。这是一个长期存在的问题,最终可以通过以前版本中对php所做的所有更改来解决。这意味着内部函数和方法将在反射中具有完整的类型信息。
重大变化如前所述:这是一个重大更新,因此会有重大变化。最好的办法是查看 升级  文档中所列的重大变化的完整列表。
许多这些突破性的更改在以前的 7.* 版本中已被弃用,因此如果你多年来一直保持 php 在最新状态,升级到 php 8 应该没那么难。
一致的类型错误 rfc之前版本在出现类型错误时,php 中的用户定义函数已经会抛出 typeerrors,但是内部函数不会这么做,而是发出警告并返回 null。从 php 8 开始,内部函数的行为已变得和用户定义函数一致。
重新分类的引擎警告 rfc许多以前仅触发警告或通知的错误已转换为适当的错误。以下警告已更改。
变量未定义:error 异常代替通知
数组索引未定义:警告代替通知
除以零:pisionbyzeroerror 异常代替警告
尝试添加/移除非对象的属性 '%s' :error 异常代替警告
尝试修改非对象的属性 '%s' :error 异常代替警告
尝试分配非对象的属性 '%s' :error 异常代替警告
从空值创建默认对象:error 异常代替警告
尝试获取非对象的属性 '%s' :警告代替通知
未定义的属性:%s::$%s:警告代替通知
无法添加元素到数组,因为下一个元素已被占用:error 异常代替警告
无法在非数组变量中销毁偏移量:error 异常代替警告
无法将标量值用作数组:error 异常代替警告
只有数组和 traversables 可以被解包:typeerror 异常代替警告
为 foreach() 提供了无效的参数:typeerror 异常代替警告
偏移量类型非法:typeerror 异常代替警告
isset 或 empty 中的偏移量类型非法:typeerror 异常代替警告
unset 中的偏移量类型非法:typeerror 异常代替警告
数组到字符串的转换:警告代替通知
资源 id#%d 用作偏移量,转换为整数 (%d):警告代替通知
发生字符串偏移量转换:警告代替通知
未初始化的字符串偏移量:%d:警告代替通知
无法将空字符串分配给字符串偏移量:error 异常代替警告
提供的资源不是有效的流资源:typeerror 异常代替警告
@ 运算符不再使致命错误不提醒此更改可能会使 php 8 之前的版本被 @ 隐藏的错误再次显示出来。请确保在生产服务器上设置了 display_errors=off !
默认错误报告级别现在的默认错误报告级别是 e_all 而不是之前的除 e_notice 和 e_deprecated 的所有内容。这意味着可能会弹出许多错误,这些错误以前曾被忽略,尽管在 php 8 之前的版本中可能已经存在。
默认 pdo 错误模式 rfc根据rfc:当前 pdo 的默认错误模式为静默。这意味着当出现 sql 错误时,除非开发人员实现了自己的显式错误处理,否则不会发出任何错误或警告,也不会引发任何异常。
此 rfc 将在 php 8 中将默认 pdo 错误模式 改为pdo::errmode_exception 。
串联优先级 rfc在 php 7.4 中已废弃的同时,此变更开始生效。如果你像这样子书写:
echo sum:  . $a + $b;
php 以前会如是理解:
echo (sum:  . $a) + $b;
php 8 将这么做故理解为此:
echo sum:  . ($a + $b);
更严格的算术和位运算类型检查php 8 以前,算术或位运算符用于数组、资源或对象是可接受的。现在不再可接受,并会抛出一个 类型错误 :
[] % [42];$object + 4;
反射方法签名变更反射类的 3 个方法签名已变更:
reflectionclass::newinstance($args);reflectionfunction::invoke($args);reflectionmethod::invoke($object, $args);
现在已变成:
reflectionclass::newinstance(...$args);reflectionfunction::invoke(...$args);reflectionmethod::invoke($object, ...$args);
升级指南指定,如果要扩展这些类,并且仍想同时支持 php 7 和 php 8,则允许以下签名:
reflectionclass::newinstance($arg = null, ...$args);reflectionfunction::invoke($arg = null, ...$args);reflectionmethod::invoke($object, $arg = null, ...$args);
几个弃用在php 7. * 的开发期间,添加了几个弃用版本,这些弃用已于 php 8 最终确定。
php 7.2 中的弃用php 7.3 中的弃用php 7.4 中的弃用以上就是php 8 中新特性以及重大调整的详细内容。
其它类似信息

推荐信息