一.新功能
1.可空类型
现在,可以通过在类型名称前面加上问号来将参数和返回值的类型声明标记为可为空。这表示和指定的类型一样,NULL
可以分别作为参数传递或作为值返回。
function test(?string $name) { var_dump($name); }
上面的$name 可为字符串或null.
2.void函数
引入了void返回类型。以void声明为返回类型的函数必须完全省略其return语句,或者使用空的return语句。NULL
不是void函数的有效返回值。
function swap(&$left, &$right): void { if ($left === $right) { return; }$tmp = $left; $left = $right; $right = $tmp; }
3.对称数组解构
速记数组语法([])现在可以用于解构分配数组(包括在 foreach中),以替代仍受支持的现有 list()语法。
<?php $data = [ [1, 'Tom'], [2, 'Fred'], ]; // list() style list($id1, $name1) = $data[0]; // [] style [$id1, $name1] = $data[0]; // list() style foreach ($data as list($id, $name)) { // logic here with $id and $name } // [] style foreach ($data as [$id, $name]) { // logic here with $id and $name }
4.类常量可见性
支持指定类常量的可见性已添加。
<?php class ConstDemo { const PUBLIC_CONST_A = 1; public const PUBLIC_CONST_B = 2; protected const PROTECTED_CONST = 3; private const PRIVATE_CONST = 4; }
5.可迭代伪类型
引入了一个称为iterable的新伪类型(类似于callable) 。它可以在参数和返回类型中使用,它可以接受实现Traversable接口的数组或对象。关于子类型,子类的参数类型可以将父级的数组声明 或Traversable声明为iterable。使用返回类型,子类可以将父级的返回类型Iterable缩小为 array或实现Traversable的对象。
<?php function iterator(iterable $iter) { foreach ($iter as $val) { // } }
6.多catch异常处理¶
现在可以使用竖线字符(|)指定每个catch块多个异常。当对来自不同类层次结构的不同异常进行相同处理时,这很有用。
<?php try { // some code } catch (FirstException | SecondException $e) { // handle first and second exceptions }
7.list()现在支持键。
现在,您可以在list()或其新的简写 []语法中指定键。这样可以使用非整数或非顺序键来解构数组。
<?php $data = [ ["id" => 1, "name" => 'Tom'], ["id" => 2, "name" => 'Fred'], ]; // list() style list("id" => $id1, "name" => $name1) = $data[0]; // [] style ["id" => $id1, "name" => $name1] = $data[0]; // list() style foreach ($data as list("id" => $id, "name" => $name)) { // logic here with $id and $name } // [] style foreach ($data as ["id" => $id, "name" => $name]) { // logic here with $id and $name }
8.支持负字符串偏移
对负字符串偏移量的支持已添加到 接受偏移量的 字符串操作函数中,以及 使用 []或{}的字符串索引中。在这种情况下,负偏移量解释为距字符串结尾的偏移量。
<?php var_dump("abcdef"[-2]); var_dump(strpos("aabbcc", "b", -3));
9.使用Closure :: fromCallable()将callables转换为Closure :
Closure 类中 引入了新的静态方法,以使 callables轻松转换为 Closure对象。
<?php class Test { public function exposeFunction() { return Closure::fromCallable([$this, 'privateFunction']); } private function privateFunction($param) { var_dump($param); } } $privFunc = (new Test)->exposeFunction(); $privFunc('some value');
10.curl 现在支持 http/2 server push.
11.新的object类型
<?php function test(object $obj) : object { return new SplQueue(); } test(new StdClass());
12. 扩展名加载
共享扩展名不再需要指定其文件扩展名(对于Unix是.so或对于Windows是.dll)。这在php.ini文件以及dl()函数中启用 。
13.抽像方法覆盖
现在,当抽象类扩展另一个抽象类时,可以重写抽象方法。
<?php abstract class A { abstract function test(string $s); } abstract class B extends A { // overridden - still maintaining contravariance for parameters and covariance for return abstract function test($s) : int; }
14.参数类型扩大¶
现在可以忽略来自重写方法和接口实现的参数类型。由于参数类型是互变的,因此这仍然符合LSP。
<?php interface A { public function Test(array $input); } class B implements A { public function Test($input){} // type omitted for $input }
15.允许对分组名称空间使用尾随逗号¶
现在可以在PHP 7.0中引入尾随逗号到组使用语法中。
<?php use Foo\Bar\{ Foo, Bar, Baz, };
16.更灵活的Heredoc和Nowdoc语法¶
文档字符串的结束标记不再需要在分号或换行符之后。另外,可以在结束标记处缩进,在这种情况下,缩进将从文档字符串中的所有行中去除。
17.数组解构支持引用赋值
TOKEN_PARSE
模式下可能引发的编译错误,但将来可能会转换更多错误。19.现在允许在函数和方法调用中使用逗号结尾。
20.多字节字符串函数新功能¶
21.属性类型声明
类属性现在支持类型声明。
<?php class User { public int $id; public string $name; } ?>
22.箭头函数
箭头函数提供了用于定义具有隐式按值作用域绑定的函数的简写语法。
<?php $factor = 10; $nums = array_map(fn($n) => $n * $factor, [1, 2, 3, 4]); // $nums = array(10, 20, 30, 40); ?>
23.有限返回类型协方差和参数类型逆变¶
现在,以下代码将起作用:
<?php class A {} class B extends A {} class Producer { public function method(): A {} } class ChildProducer extends Producer { public function method(): B {} } ?>
24.空合并赋值运算符¶
代替如下写法:
$data['date'] = $data['date'] ?? new DateTime();
你可以这样做:
$data['date'] ??= new DateTime();
<?php $array['key'] ??= computeDefault(); // is roughly equivalent to if (!isset($array['key'])) { $array['key'] = computeDefault(); } ?>
25.数组内解包
<?php $parts = ['apple', 'pear']; $fruits = ['banana', 'orange', ...$parts, 'watermelon']; // ['banana', 'orange', 'apple', 'pear', 'watermelon']; ?>
26.数值文字分隔符
数字文字可以在数字之间包含下划线。
<?php 6.674_083e-11; // float 299_792_458; // decimal 0xCAFE_F00D; // hexadecimal 0b0101_1111; // binary ?>
27.弱引用
弱引用使程序员可以保留对对象的引用,这不会阻止对象被破坏。
28.FFI外部函数接口
FFI是一个新扩展,它提供了一种简单的方法来调用本机函数,访问本机变量以及创建/访问C库中定义的数据结构。
29.预加载
预加载是PHP核心的一个惊人的补充,可以带来一些重大的性能改进。
简而言之:如果您今天使用的是框架,则必须在每次请求时加载和重新编译其文件。预加载允许服务器在启动时在内存中加载PHP文件,并使它们永久可用于所有后续请求。
性能提升当然需要付出代价:如果预加载文件的来源发生变化,则必须重新启动服务器。
此特性可以大幅提升IO性能,性能提升约30-50%,甚至更高
30.自定义对象序列化
添加了用于自定义对象序列化的新机制,该机制使用了两个新的魔术方法:__serialize 和__unserialize。
<?php // Returns array containing all the necessary state of the object. public function __serialize(): array; // Restores the object state from the given data array. public function __unserialize(array $data): void; ?>
31.没有参数的数组合并函数¶
32.在对象和数组类型转换中转换数字键
现在,在将数组转换为对象以及将对象转换为数组时(通过显式转换或通过settype()),可以更好地处理数字键 。
这意味着现在可以访问从数组转换为对象的整数(或字符串整数)键:
<?php // array to object $arr = [0 => 1]; $obj = (object)$arr; var_dump( $obj, $obj->{'0'}, // now accessible $obj->{0} // now accessible );
现在可以访问从对象转换为数组的整数(或字符串整数)键:
<?php // object to array $obj = new class { public function __construct() { $this->{0} = 1; } }; $arr = (array)$obj; var_dump( $arr, $arr[0], // now accessible $arr['0'] // now accessible );
二.向后不兼容的改变
1.传递过少的函数参数¶
以前,如果调用的用户定义函数的参数太少,将发出警告。现在,此警告已升级为错误异常。此更改仅适用于用户定义的功能,不适用于内部功能。例如:
<?php function test($param){} test();
2.禁止动态调用范围内省函数
禁止动态调用某些函数(以 $ func()或array_map('extract',...)等形式)。这些功能检查或修改了另一个范围,并表现出模棱两可和不可靠的行为。函数如下
- assert() - with a string as the first argument
- compact()
- extract()
- func_get_args()
- func_get_arg()
- func_num_args()
- get_defined_vars()
- mb_parse_str() - with one arg
- parse_str() - with one arg
<?php (function () { $func = 'func_num_args'; $func(); })();
上面的示例将输出:
警告:无法在%s的第%d行动态调用func_num_args()
3.无效的类,接口和trait名称¶
以下名称不能用于命名类,接口或trait:
- void
- iterable
4.数字字符串转换现在符合科学计数法¶
现在,数字字符串的整数运算和转换都遵循科学计数法。这也包括(INT)转换操作,和以下函数intval() (where the base is 10), settype(), decbin(), decoct(), and dechex().
5.修复了mt_rand()算法¶
6.rand() aliased to mt_rand() and srand() aliased to mt_srand() ¶
现在已将 rand()和 srand()分别设为 mt_rand()和 mt_srand()的别名。这意味着以下函数的输出已更改: rand(), shuffle(), str_shuffle()和 array_rand()。
7.禁止标识符中的ASCII删除控制字符¶
ASCII删除控制字符(0x7F)不能再用于未加引号的标识符中。
8.不要在不完整的对象上调用析构函数
现在,对于在执行其构造函数期间引发异常的对象,永远不会调用析构函数。在以前的版本中,此行为取决于对象是否在构造函数外部引用(例如,通过异常回溯)。
9.call_user_func()处理引用参数
call_user_func() 现在始终在调用预期引用为参数的函数时生成警告。以前,这取决于呼叫是否完全限定。
此外,在这种情况下,call_user_func() 和call_user_func_array() 将不再中止函数调用。将发出"预期引用"警告,但呼叫将照常进行。
10.字符串不再支持空索引运算符
将空索引运算符应用于字符串(例如$ str [] = $ x)会引发致命错误,而不是无声地转换为数组。
11.通过对空字符串的字符串索引访问进行赋值
现在,按字符对空字符串进行字符串修改的工作方式类似于非空字符串,即,写入超出范围的偏移量时,将用空格填充字符串,其中非整数类型将转换为整数,并且仅分配字符串的第一个字符用来。以前,空字符串在其中被静默地视为一个空数组。
<?php $a = ''; $a[10] = 'foo'; var_dump($a); ?>
上面的示例在PHP 7.0中的输出:
array(1){ [10] => 字符串(3)“ foo” }
以上示例在PHP 7.1中的输出:
字符串(11)“ f”
12.通过引用赋值在自动创建元素时的数组顺序已更改 ¶
通过在按引用分配中引用这些元素来自动创建这些元素时,数组中元素的顺序已更改。例如:
<?php $array = []; $array["a"] =& $array["b"]; $array["b"] = 1; var_dump($array); ?>
上面的示例在PHP 7.0中的输出:
array(2){ [“”“] => &int(1) [” b“] => &int(1) }
以上示例在PHP 7.1中的输出:
array(2){ [“” b“] => &int(1) [” a“] => &int(1) }
13.相等元素的排序顺序
内部排序算法已得到改进,这可能导致元素的排序顺序与以前相比有所不同。
注意事项:不要依赖比较相等的元素的顺序;它可能随时更改。
14.unserialize()的$options参数
现在严格类型化unserialize()的$ options参数 的allowed_classes元素 ,即,如果给出除数组或布尔值以外的任何内容,unserialize()返回并发出一个。 FALSE
E_WARNING
15.DateTime构造函数包含微秒
日期时间和日期时间不可变现在正确合并微秒时,从当前时间构造,无论是显式还是使用相对字符串(例如"下个月的第一天")。这意味着两个新创建的实例的天真比较现在更有可能返回 FALSE 而不是 TRUE:
<?php new DateTime() == new DateTime(); ?>
现在许多扩展中的致命错误将变为Error异常抛出。
17.词汇绑定变量不能重用名称
通过use构造 绑定到闭包的变量不能使用与任何superglobals,$ this或任何参数相同的名称 。例如,所有这些函数定义都将导致致命错误:
<?php $f = function () use ($_SERVER) {}; $f = function () use ($this) {}; $f = function ($param) use ($param) {};
18.JSON编码和解码
<?php var_dump(json_decode(json_encode(['' => 1])));
上面的示例将输出类似于以下内容的内容:
object(stdClass)#1(1){ [“”] => int(1) }
当将JSON_UNESCAPED_UNICODE
标志提供给 json_encode()时,序列U + 2028和U + 2029现在被转义。
19.更改mb_ereg()和mb_eregi() 参数语义
如果没有匹配项 ,则mb_ereg()和 mb_eregi()函数(regs
)的第三个参数现在将设置为空数组。以前,该参数不会被修改。
20.防止number_format()返回负零¶
<?php var_dump(number_format(-0.01)); // now outputs string(1) "0" instead of string(2) "-0"
21.禁止传递NULL
给get_class() ¶
以前,传递NULL
给get_class()函数将输出封闭类的名称。现在,此行为已删除,E_WARNING
将改为输出。为了实现与以前相同的行为,应仅省略该参数。
22.计数不可数类型时警告
一个E_WARNING
试图当现在将发射 计数()非可数的类型(这包括 的sizeof()别名的功能)。
<?php var_dump( count(null), // NULL is not countable count(1), // integers are not countable count('abc'), // strings are not countable count(new stdclass), // objects not implementing the Countable interface are not countable count([1,2]) // arrays are countable );
The above example will output:
Warning: count(): Parameter must be an array or an object that implements Countable in %s on line %d Warning: count(): Parameter must be an array or an object that implements Countable in %s on line %d Warning: count(): Parameter must be an array or an object that implements Countable in %s on line %d Warning: count(): Parameter must be an array or an object that implements Countable in %s on line %d int(0) int(1) int(1) int(1) int(2)
23.已关闭资源的 gettype()返回值
以前,在封闭的资源上使用gettype()会返回“未知类型”的字符串。现在,将返回一个字符串 “ resource(closed)”。
24.is_object() and __PHP_Incomplete_Class ¶
以前,在__PHP_Incomplete_Class类上使用is_object()将返回 FALSE。现在,将返回 TRUE。
25.检查traits的默认属性值
对默认traits属性值的兼容性检查将不再执行强制转换
26."object"用作类名
object名称以前在PHP 7.0中被软保留。现在,这是硬保留的,禁止将其用作类,特征或接口名称。
27.array_unique()与 ¶SORT_STRING参数
虽然array_unique()与SORT_STRING
以前复制的阵列和移除的非唯一的元素(不事后包装阵列),现在一个新的数组是通过将独特的元素构建的。这可能导致不同的数字索引。
28.bcmod()随浮点数变化
29.散列函数和非加密散列值¶
该hash_hmac() ,hash_hmac_file() , hash_pbkdf2() ,和hash_init() (含 HASH_HMAC
)函数不再接受非加密散列值。
30.json_decode()函数选项 ¶
json_decode()函数的option, JSON_OBJECT_AS_ARRAY
现在用于如果所述第二参数(assoc)是NULL
。以前, JSON_OBJECT_AS_ARRAY
总是被忽略。
32.对date_parse()和date_parse_from_format()的更改¶
由date_parse()和 date_parse_from_format()返回的数组 的zone元素现在代表秒而不是分钟,并且其符号反转。例如-120 现在是7200。
33.Heredoc / Nowdoc结尾标签解释¶
由于引入了灵活的heredoc / nowdoc语法,因此在正文中包含结尾标签的doc字符串可能会导致语法错误或解释更改。例如:
<?php $str = <<<FOO abcdefg FOO FOO; ?>
缩进的FOO以前没有任何特殊意义。现在将其解释为heredoc字符串和以下FOO的结尾;将导致语法错误。始终可以通过选择字符串内容中未出现的结束标签来解决此问题。
34.Switch中的continue问题警告
现在,针对开关控制流结构的continue语句将生成警告。在PHP中,此类 continue语句等效于 break,而 在其他语言中,它们的行为与continue 2相同。
<?php while ($foo) { switch ($bar) { case "baz": continue; // Warning: "continue" targeting switch is equivalent to // "break". Did you mean to use "continue 2"? } } ?>
35.ArrayAccess上整数字符串键的严格解释
类型为$ obj [“ 123”]的数组访问,其中 $ obj实现ArrayAccess并且 “ 123”是整数字符串常量将不再导致隐式转换为整数,即 $ obj-> offsetGet(“ 123”)将而不是$ obj-> offsetGet(123)被调用 。这与非文学作品的现有行为相匹配。数组的行为不会受到任何影响,它们会继续将整数字符串键隐式转换为整数。
36.静态属性不再由引用分配分隔
在PHP中,除非在子类中显式覆盖静态属性,否则静态属性在继承的类之间共享。但是,由于存在实现工件,因此可以通过分配引用来分离静态属性。此漏洞已得到修复。
<?php class Test { public static $x = 0; } class Test2 extends Test { } Test2::$x = &$x; $x = 1; var_dump(Test::$x, Test2::$x); // Previously: int(0), int(1) // Now: int(1), int(1) ?>
37.通过数组和属性访问返回引用是立即展开
现在,将数组访问和属性访问返回的引用展开为访问的一部分。这意味着不再可能在访问和使用访问值之间修改引用:
<?php $arr = [1]; $ref =& $arr[0]; var_dump($arr[0] + ($arr[0] = 2)); // Previously: int(4), Now: int(3) ?>
38.raversables的参数解包与非整数key不再支持
参数解压缩停止了与带有非整数键的Traversable一起使用。以下代码偶然在PHP 5.6-7.2中工作。
<?php function foo(...$args) { var_dump($args); } function gen() { yield 1.23 => 123; } foo(...gen()); ?>
39.getimagesize()和相关函数现在将BMP图像的mime类型报告为 image / bmp而不是 image / x-ms-bmp,因为前者已在IANA上注册(请参阅 »RFC 7903)。
40.bcmul()和 bcpow()现在返回具有请求的小数位数的数字。以前,返回的数字可能省略了尾随的十进制零。
41.IMAP, POP3 and NNTP ¶
默认情况下,禁用rsh / ssh登录。如果要启用它们,请使用imap.enable_insecure_rsh。请注意,IMAP库它们传递给前不过滤的邮箱名RSH / SSH 命令,因此不受信任的数据传递给有此功能 RSH / SSH启用是不安全的。
42.多字节字符串
由于增加了对命名捕获的支持,使用命名捕获的mb_ereg _ *() 模式将表现出不同的行为。特别是命名捕获将成为匹配的一部分,并且mb_ereg_replace() 将解释其他语法。有关更多信息,请参见命名捕获。
43.MySQL改进的扩展
现在,准备好的语句可以正确报告带有小数点说明符的DATETIME,TIME和 TIMESTAMP列的小数秒 (例如 ,使用微秒时为TIMESTAMP(6))。以前,小数秒部分只是从返回值中省略了。
44.MySQL函数(PDO_MYSQL)
现在,准备好的语句可以正确报告带有小数点说明符的DATETIME,TIME和 TIMESTAMP列的小数秒 (例如 ,使用微秒时为TIMESTAMP(6))。以前,小数秒部分只是从返回值中省略了。请注意,这仅会影响已关闭模拟准备的PDO_MYSQL的使用(例如,使用本机准备功能)。使用具有PDO::ATTR_EMULATE_PREPARES
= TRUE
(默认设置)的连接的语句不受已修复的错误的影响,并且已经从引擎获取了正确的小数秒值。
45.反射
反射导出到字符串现在分别使用 int和bool而不是 integer和boolean。
46.标准PHP库(SPL)
如果SPL自动加载器引发异常,将不会执行以后的自动加载器。以前,所有自动加载器均已执行,并且异常被链接在一起。
47.SimpleXML
现在,尝试将null,bool, int,float或resource类型的值用作数组(例如$ null [“ key”])将生成一个通知。
49.get_declared_classes() 函数不再返回尚未实例化的匿名类。
50.fn关键字
fn现在是保留关键字。特别是,它不能再用作函数或类名。它仍然可以用作方法或类常量名称。
51.文件末尾的<?php标记
文件末尾的<?php(不带换行符)现在将被解释为一个开放的PHP标记。以前,它要么被解释为一个短的开始标记,然后是文字php并导致语法错误(使用short_open_tag = 1),要么被解释为文字<?php字符串(使用short_open_tag = 0)。
52.序列化
o序列化格式已被删除。由于PHP从未生产过它,因此可能只会破坏手工制作的字符串的反序列化。
52.密码算法常量
密码哈希算法标识符现在是可为空的字符串,而不是整数。
PASSWORD_DEFAULT
是int 1;现在是NULL
PASSWORD_BCRYPT
是int 1;现在是字符串“ 2y”PASSWORD_ARGON2I
是int 2;现在是字符串“ argon2i”PASSWORD_ARGON2ID
是int 3;现在是字符串“ argon2id”
正确使用常量PASSWORD_DEFAULT,PASSWORD_BCRYPT,PASSWORD_ARGON2I和PASSWORD_ARGON2ID的应用程序将继续正常运行。
如果操作失败, fread()和 fwrite()现在将返回FALSE
。以前返回空字符串或0。EAGAIN / EWOULDBLOCK不被视为失败。
现在,这些功能还会引起故障通知,例如在尝试写入只读文件资源时
55.日期和时间
在DateTime或DateTimeImmutable 实例上 调用var_dump()或类似方法 将不再在对象上留下可访问的属性。
DateInterval对象的 比较(使用==,<等)现在将生成警告并始终返回FALSE
。以前,所有DateInterval 对象都被认为是相等的,除非它们具有属性。
56.MySQLi
取而代之的是mysqli :: stat(),删除了 未公开的mysqli :: $ stat属性。
57.标准PHP库(SPL)
现在,在ArrayObject实例上 调用get_object_vars()将始终返回ArrayObject 本身(或子类)的属性。以前,除非 指定了标志,否则它返回包装的数组/对象的值。 ArrayObject::STD_PROP_LIST
其他受影响的操作是:
(数组)演员表不受影响。它们将继续返回包装的数组或ArrayObject 属性,具体取决于是否使用了该ArrayObject::STD_PROP_LIST
标志。
如果传递零,则 SplPriorityQueue :: setExtractFlags()将引发异常。以前,这将在下一次提取操作中产生可恢复的致命错误。
现在 ,除了Serializable接口之外,ArrayObject,ArrayIterator, SplDoublyLinkedList和SplObjectStorage还支持__serialize()和__unserialize()机制。这意味着在较旧的PHP版本上创建的序列化有效负载仍然可以反序列化,但是较旧的版本将无法理解由PHP 7.4创建的新有效负载。
58.Tokenizer
59.$this的不一 致性更改
60.不区分大小写的常量
不区分大小写的常量的声明已被弃用。现在将其TRUE
作为第三个参数传递 给define()会生成弃用警告。不建议使用不区分大小写的常量(其大小写与声明不同)。
61.正则表达式(与Perl兼容)
该PCRE扩展已经升级到PCRE2,这可能会引起轻微的行为改变(例如,在课堂字符范围现在更严格的解释),并增强现有的正则表达式语法。
当在同一字符串(但可能有不同的偏移量)上重复调用UTF-8模式下的preg_match()(“ u”修饰符)时,将只检查一次UTF-8有效性。
62.str_getcsv() 的行为已相应调整(以前,空字符串与使用默认字符串相同)。
最后更新于 2019年12月1日