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 版本中不能反序列化。