编程

PHP 8.1: Serializable 接口弃用

1309 2023-09-08 11:45:00

PHP 支持 serializeunserialize 函数用于将类对象、数组及其他标量数据转换为序列化字符串格式,及从序列化字符串中重建。

PHP 类可以提供他们自己的序列化实现。比如,类可以排除特定敏感信息,不将其添加到序列化字符串中,或者类可以从序列化文本中获取的服务器 URL 重新建立与远程服务器的连接。

PHP 类有三种方式提供自定义序列化逻辑:

  • __sleep__wakeup 魔术方法
  • Serializable 接口及 Serializable::serializeSerializable::unserialize 方法 (自 PHP 5.1 起)
  • __serialize__unserialize 魔术方法 (自 PHP 7.4 起)

实现 __serialize__unserialize 方法是推荐的方式,因为它避免了 __sleep/_wakeup 方法和 Serializable接口的一些陷阱。

在 PHP 8.1, 实现 Serializable 接口而不实现 __serialize__unserialize 方法将被弃用。

class Test implements Serializable{
    public function serialize() {}
    public function unserialize($data) {}
}
Deprecated: Test implements the Serializable interface, which is deprecated. Implement __serialize() and __unserialize() instead (or in addition, if support for old PHP versions is necessary) in ... on line ...
  • JsonSerializable 接口不受影响。
  • 从 PHP 8.0 起,类魔术方法签名严格执行。

早在2019年,就有人提议添加两个新的魔术方法 __serialize__unserialize ,因为 __wakeup + __sleepSerializable 接口方法由于实现复杂性及其错误行为而不理想。 

PHP 8.1中的这种弃用是这一变化的延续,即在没有新的魔术方法的情况下弃用实现 Serializable 接口,并最终在PHP 9.0中删除 Serializable 接口。

如果一个类同时实现 Serializable 接口方法和魔术方法,则魔术方法优先,并且不会发出弃用通知。

在 PHP 7.4 及更高版本中,__serialize__unserialize 方法是在 serialize()/userialize 调用期间执行的,而不是 Serializable 接口中的 serialize/unserialized 方法。PHP 8.1中也不会有任何弃用通知。

class Test implements Serializable{

    public function __serialize(): array {}
    public function __unserialize(array $data): void {}

    public function serialize(): array {}
    public function unserialize(string $data): void {}

}

相关变更

  • PHP 8.1: PDO::FETCH_SERIALIZE 弃用

向后兼容性影响

请注意,如果类还实现了 __serialize__unserialize 方法,则不会发出弃用通知。

如果一个类同时实现 Serializable 接口方法和魔术方法,则魔术方法优先。

在使用 PHP 7.4 作为最低版本的应用程序上,可以安全地放弃 Serializable 接口实现,并实现新的 __serialize__unserialize 方法。

在必须支持早于 PHP 7.4 的 PHP 版本的应用程序上,需同时实现 Serializable 接口(将在 PHP<=7.3 上使用)和 __serialize/ __unserialize方法(适用于 PHP 7.4、8.0及更高版本)。