PHP 8.4.2 Released!

不向后兼容的变更

当传递参数过少时将抛出错误

在过去如果我们调用一个用户定义的函数时,提供的参数不足,那么将会产生警告(warning)。现在,这个警告被提升为错误异常(Error exception)。这个变更仅对用户定义的函数生效,并不包含内置函数。例如:

<?php
function test($param){}
test();

以上示例的输出类似于:

Fatal error: Uncaught ArgumentCountError: Too few arguments to function test(), 0 passed in %s on line %d and exactly 1 expected in %s:%d

禁止动态调用作用域内的内省(introspection)函数

禁止动态调用($func()array_map('extract', ...) 的形式等)某些函数。这些函数会检查或修改另一个作用域,并呈现出不明确且不可靠的行为。函数如下:

<?php
(function () {
$func = 'func_num_args';
$func();
})();

以上示例会输出:

Warning: Cannot call func_num_args() dynamically in %s on line %d

无效的 class、interface 和 trait 名称

下列名称不能用于 class、interfaces 或 traits 名:

数字字符串转换现在遵循科学记数法

现在在数字字符串上执行整数运算和转换会考虑科学计数法。这还包括 (int) 类型转换操作以及以下函数:intval()(基数为 10)、settype()decbin()decoct()dechex()

修复 mt_rand() 算法

mt_rand() 现在默认使用修复版本的梅森旋转算法。如果依赖于 mt_rand() 的确定输出,则可以使用 MT_RAND_PHP 作为 mt_srand() 的可选第二个参数,以保留旧的(不正确的)实现。

rand()mt_rand() 的别名以及 srand()mt_srand() 的别名

rand()srand() 现已成为 mt_rand()mt_srand() 的别名。这意味着以下函数已经更改:rand()shuffle()str_shuffle()array_rand()

禁止在标识符中使用 ASCII 删除控制字符

ASCII 删除控制字符(0x7F)不能用于未加引号的标识符中。

error_log 更改为 syslog

如果 error_log ini 设置为 syslog,PHP 错误等级会映射到 syslog 错误级别。这在错误日志中带来了更好的区分,与之前相反,之前所有的错误只记录了错误级别。

在不完整的对象上不再调用析构方法

对于在执行构造方法时抛出异常的对象,现在析构方法绝不会被调用。在先前的版本中,这个行为取决于对象是否在构造方法以外的地方呗引用(例如一个错误堆栈回溯)

call_user_func() 不再支持对传址的函数的调用

call_user_func() 现在在调用一个以引用作为参数的函数时将始终产生一个警告。先前这取决于这个调用行为是否完全符合条件。

此外,call_user_func()call_user_func_array() 在这种情况下将不再中断函数调用。现在会出现包含“expected reference”的警告信息,但函数调用将正常进行。

字符串不再支持空索引操作符

对字符串使用一个空索引操作符(例如$str[] = $x)将会抛出一个致命错误,而不是静默地将其转为一个数组。

ini 配置项移除

下列 ini 配置项已经被移除:

  • session.entropy_file
  • session.entropy_length
  • session.hash_function
  • session.hash_bits_per_character

在引用赋值期间自动创建元素时的数组排序已更改

当通过引用赋值自动创建这些元素时,数组中元素的顺序就会发生变化。例如:

<?php
$array
= [];
$array["a"] =& $array["b"];
$array["b"] = 1;
var_dump($array);
?>

以上示例在 PHP 7.0 中的输出:

array(2) {
  ["a"]=>
  &int(1)
  ["b"]=>
  &int(1)
}

以上示例在 PHP 7.1 中的输出:

array(2) {
  ["b"]=>
  &int(1)
  ["a"]=>
  &int(1)
}

相等元素的排序顺序

内部排序算法已得到改进,这可能会导致元素比较相等的排序顺序与以前不同。

注意:

不要依赖比较相等的元素的顺序;它可能随时改变。

E_RECOVERABLE 错误的错误消息

E_RECOVERABLE 错误的错误消息已从“可捕获的致命错误”更改为“可恢复的致命错误”。

unserialize() 的 $options 参数

unserialize() 的 $options 参数的 allowed_classes 元素现在是严格类型,也就是说,如果指定了 arraybool 以外的任何内容,则 unserialize() 返回 false 并发出 E_WARNING

DateTime 构造方法包含微秒

DateTimeDateTimeImmutable 现在构造当前时间时正确地包含微秒,无论是明确指定的还是使用相对字符串(例如 "first day of next month")。这意味着两个新创建的实例的原生比较现在更有可能返回 false 而不是 true

<?php
new DateTime() == new DateTime();
?>

核心错误转换为 Error 异常

在 Date 扩展中,DateTimeDatePeriod 类的无效序列化数据或者序列化数据的时区初始化失败,现在将从 __wakeup()__set_state() 方法抛出 Error 异常,而不是导致致命错误。

在 DBA 扩展中,如果键没有完全包含两个元素,数据修改函数(例如 dba_insert())现在将抛出 Error 异常,而不是触发可捕获的致命错误。

在 DOM 扩展中,无效的模式或 RelaxNG 验证上下文现在将引发 Error 异常,而不是导致致命错误。同样,尝试注册不继承适宜基类的节点类、尝试读取无效属性或写入只读属性,现在也将引发 Error 异常。

在 IMAP 扩展中,长度超过 16385 字节的电子邮件地址将引发 Error 异常,而不是导致致命错误。

在 Intl 扩展中,在调用父级方法之前,在继承 Collator 的类中调用父级构造方法失败,现在将抛出 Error 而不是可恢复的致命错误。此外克隆 Transliterator 对象时,如果无法克隆内部 transliterator,将抛出 Error 异常,而不会导致致命错误。

在 LDAP 扩展中,向 ldap_batch_modify() 提供未知的修改类型现在将引发 Error 异常,而不是导致致命错误。

在 mbstring 扩展中,如果提供了无效的 PHP 表达式并且使用了“e”选项,mb_ereg()mb_eregi() 函数现在将引发 ParseError 异常。

在 Mcrypt 扩展中,如果 mcrypt 无法初始化,mcrypt_encrypt()mcrypt_decrypt() 现在将抛出 Error 异常,而不是导致致命错误。

在 mysqli 扩展中,尝试读取无效属性或写入只读属性现在将引发 Error 异常,而不是导致致命错误。

在反射扩展中,检索 reflection 对象或检索对象属性失败现在将引发 Error 异常,而不是导致致命错误。

在 Session 扩展中,当调用必须生成会话 ID 的函数时,自定义会话处理程序不返回字符串格式的会话 ID 现在将引发 Error 异常,而不是导致致命错误。

在 SimpleXML 扩展中,创建未命名或重复的属性现在将引发 Error 异常,而不是导致致命错误。

在 SPL 扩展中,尝试克隆 SplDirectory 对象现在将引发 Error 异常,而不是导致致命错误。同理,在迭代对象时调用 ArrayIterator::append() 现在也会引发 Error 异常。

在标准扩展中,将字符串作为其第一个参数时,assert() 函数现在将抛出 ParseError 异常,而不是在 PHP 代码无效时导致可捕获的致命错误。同理,在类作用域之外调用 forward_static_call() 现在将引发 Error 异常。

在 Tidy 扩展中,手动创建 tidyNode 现在将抛出 Error 异常,而不是导致致命错误。

在 WDDX 扩展中,序列化时的循环引用现在将引发 Error 异常,而不是导致致命错误。

在 XML-RPC 扩展中,序列化时的循环引用现在将抛出 Error 异常实例,而不是导致致命错误。

在 Zip 扩展中,如果 glob 支持无效,ZipArchive::addGlob() 方法现在将引发 Error 异常,而不是导致致命错误。

词法绑定变量不能重用名字

通过 use 构造绑定到 closure 的变量不能使用与任何 superglobals$this 或任何参数相同的名称。例如,所有这些函数定义都会导致致命错误:

<?php
$f
= function () use ($_SERVER) {};
$f = function () use ($this) {};
$f = function ($param) use ($param) {};

long2ip() 参数类型更改

long2ip() 现在接受 int 而不是 string

JSON 编/解码

serialize_precision ini 设置现在控制编码 float 时的序列化精度。

解码空键(empty key)现在会产生空属性,而不是 _empty_ 作为属性名称。

<?php
var_dump
(json_decode(json_encode(['' => 1])));

以上示例的输出类似于:

object(stdClass)#1 (1) {
  [""]=>
  int(1)
}

当向 json_encode() 提供 JSON_UNESCAPED_UNICODE flag 时,现在转义序列 U+2028 和 U+2029。

更改 mb_ereg()mb_eregi() 参数语义

如果没有匹配到内容,mb_ereg()mb_eregi() 函数(regs)的第三个参数现在将设置为空数组。以前,不会修改该参数。

放弃对 sslv2 stream 的支持

sslv2 stream 现已在 OpenSSL 中删除。

在编译时禁止 "return;" 用于类型化返回

在声明返回类型的函数中,没有参数的 return 语句现在触发 E_COMPILE_ERROR(除非返回类型声明为 void),即使永远不会到达 return 语句。

添加备注

用户贡献的备注 5 notes

up
46
love at sickpeople dot se
8 years ago
For anyone migrating from 5.x to 7.1:

About "Array ordering when elements are automatically created during by reference assignments has changed" on this page

(http://php.net/manual/en/migration71.incompatible.php#migration71.incompatible.array-order)

The behaviour of 7.1 is THE SAME as of PHP 5. It is only 7.0 that differs.

See https://3v4l.org/frbUc

<?php

$array
= [];
$array["a"] =& $array["b"];
$array["b"] = 1;
var_dump($array);
up
34
kees at twekaers dot net
7 years ago
The backwards incompatible change 'The empty index operator is not supported for strings anymore' has a lot more implications than just a fatal error on the following code

<?php
$a
= "";
$a[] = "hello world";
var_dump($a);
?>

This will give a fatal error in 7.1 but will work as expected in 7.0 or below and give you: (no notice, no warning)

array(1) {
[0]=>
string(11) "hello world"
}

However, the following is also changed:

<?php
$a
= "";
$a[0] = "hello world";
var_dump($a);
// 7.1: string(1) "h"
// pre-7.1: array(1) { [0]=> string(11) "hello world" }

$a = "";
$a[5] = "hello world";
var_dump($a);
// 7.1: string(6) " h"
// pre-7.1: array(1) { [0]=> string(11) "hello world" }

?>
up
17
m dot r dot sopacua at gmail dot com
7 years ago
"OMFG! Why was session.hash_function removed?!? Dude!"

https://wiki.php.net/rfc/session-id-without-hashing

There. Saved ya a search.
up
2
mikem at gmail dot com
7 years ago
ArgumentCountError - this modification is the main reason to avoid this version on older projects.
up
0
david at artefactual dot com
5 years ago
Regarding the ArgumentCountError, PHP 7.1+ does still support user functions with a variable number of arguments, using the "func(...$args) {}" syntax, see: https://www.php.net/manual/en/functions.arguments.php#functions.variable-arg-list
To Top