PHP 8.3: unserialize(): E_NOTICE 错误升级为 E_WARNING
PHP 提供了 serialize 和 unserialize() 函数用以将 PHP 值(字符串、整型值、对象、NULL、数组、枚举等)系列化为字符串表示,及从字符串中重建 PHP 值。
$data = ['apple', 'banana', 'orange'];
$serialized = serialize($data);
// "a:3:{i:0;s:5:"apple";i:1;s:6:"banana";i:2;s:6:"orange";}"
$restoredData = unserialize($serialized);
// ['apple', 'banana', 'orange']PHP 8.3 之前,传入无效的字符串到 unserialize() 函数在特定情况下(比如语法错误)将发出 PHP 通知(E_NOTICE)。自 PHP 8.3 起,将变成发出警告(E_WARNING)。此外,serialize() 函数的特定错误条件也改成了 发送 E_WARNING 警告。
unserialize("invalid-string");- PHP Notice: unserialize(): Error at offset 0 of 14 bytes
+ PHP Warning: unserialize(): Error at offset 0 of 14 bytes理想情况下,未能对给定字符串的反序列化应该是一个硬失败,并且应该抛出异常。然而,为了保持向后兼容性并简化升级路径,PHP 8.3中的错误级别有所增加,未来可能会升级它以抛出异常。
错误条件不一致
并非所有unserialize()失败都会发送E_NOTICE错误。比如,反系列化超过最大深度限制(PHP7.4起,通过 INI 设置unserialize_max_depth项进行配置)的字符串已经发送E_WARNING警告。这种情况将不作调整并继续发出E_WARNING错误。
受影响的错误条件
从 PHP 8.3 起,以下三个先前发出 E_NOTICE 的错误条件已更改为发出E_WARNING:
- 传递的字符串中存在语法错误(有时是由不正确的序列化处理程序引起的)
unserialize('invalid string');- PHP Notice: unserialize(): Error at offset 0 of 12 bytes
+ PHP Warning: unserialize(): Error at offset 0 of 12 bytes- 使用
__unserialize魔术方法的自定义反系列化处理程序失败;例如__unserialize()方法没有返回任何值
class Test {
public function __unserialize(array $data) { } // Does not return anything
}- PHP Notice: unserialize(): Unexpected end of serialized data
+ PHP Warning: unserialize(): Unexpected end of serialized data- 从
__sleep()魔术方法返回同一变量两次,导致名称冲突
class Test {
public $foo = 'test';
public function __sleep() {
return array("foo", "foo"); // Same value returned twice
}
}
serialize(new Test());- PHP Notice: serialize(): "foo" is returned from __sleep() multiple times
+ PHP Warning: serialize(): "foo" is returned from __sleep() multiple times向后兼容性影响
在 PHP 8.0 中,PHP 的默认错误报告级别更改为 E_ALL。除非在自定义 INI 文件中更改了 error_reporting值,否则除了严重性的更改之外,这不应该引入任何新的错误。
由于严重性的更改,以前忽略 E_NOTICE 错误的自定义错误处理程序可能会遇到新的 E_WARNING。强烈建议不要调整错误处理程序以忽略这些警告,而是评估警告并修正无效的错误条件。
一个值得注意的警告是,PHP 8.1 为 Enum 引入了新的序列化模式。序列化枚举采用 E:… 格式,并且在 PHP 8.1 之前的 PHP 版本中不能反序列化。