PHP 8.3 语法变化 - unserialize 将 E_NOTICE 错误升级为 E_NOTICE 错误

作者: 温新

图书: 【PHP 8.3 新特性】

阅读: 586

时间: 2024-11-21 11:28:37

hi,我是温新,一名 PHPer

PHP提供 serializeunserialize 函数来序列化任何 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 Warning:  unserialize(): Error at offset 0 of 14 bytes

理想情况下,无法反序列化给定字符串应该是一个硬失败,并抛出一个异常。然而,为了保持向后兼容并简化升级路径,在 PHP 8.3 中提高了错误级别,未来可能会升级为抛出异常。

错误条件不一致

并非所有的 unserialize() 失败都会发出 E_NOTICE 错误。例如,反序列化超过最大深度限制的字符串(自 PHP 7.4 起使用unserialize_max_depth INI 设置进行配置)已经发出 E_WARNING。此情况继续发出 E_WARNING 错误,并且没有改变。

受影响的错误条件

自 PHP 8.3 起,以下三个之前发出 E_NOTICE 的错误条件更改为发出 E_WARNING:

  • 传递的字符串中的语法错误(有时由错误的序列化处理程序引起)

    unserialize('invalid string');
    
    PHP Warning:  unserialize(): Error at offset 0 of 12 bytes
    
  • 使用 __unserialize 魔术方法的自定义 unserialize 处理程序失败;例如,__unserialize() 方法未返回任何值。

    class Test {
        public function __unserialize(array $data) { } // Does not return anything
    }
    
    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 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 枚举引入了新的序列化模式。序列化的枚举采用 E:... 格式,并且不能在 PHP 8.1 之前的版本中反序列化。

请登录后再评论