php序列化中serializable接口与__sleep()/__wakeup()互斥,优先级为serializable > __serialize() > __sleep();实现serializable则完全忽略__sleep/__wakeup,适用于敏感字段过滤等高级控制。

PHP 序列化过程中,Serializable 接口与 __sleep()/__wakeup() 互斥使用,不是执行顺序先后的问题,而是“二选一”的机制。
当一个类同时实现了 Serializable 接口并定义了 __sleep() 方法时,PHP 只会调用 Serializable::serialize(),完全忽略 __sleep();同理,反序列化时只调用 unserialize(),不触发 __wakeup()。
✅ 什么情况下走 Serializable?
- 类显式声明
implements Serializable - 正确实现两个方法:
serialize()和unserialize() - 此时
serialize($obj)会调用你写的serialize()方法,返回任意字符串(非标准格式也可) -
unserialize($str)会调用你写的unserialize()方法,负责重建对象状态
class User implements Serializable {
private $name;
private $token; // 敏感字段,不存
public function __construct($name, $token) {
$this->name = $name;
$this->token = $token;
}
public function serialize() {
return serialize(['name' => $this->name]); // 只序列化 name
}
public function unserialize($data) {
$arr = unserialize($data);
$this->name = $arr['name'];
$this->token = 'renewed'; // 反序列化时重置 token
}
}
✅ 什么情况下走 __sleep() / __wakeup()?
- 类未实现
Serializable - 但定义了
public function __sleep()和/或public function __wakeup() -
serialize()会先调__sleep(),它必须返回需序列化的属性名数组 -
unserialize()后立即调__wakeup(),用于恢复资源、重连等
class DatabaseConnection {
private $host, $user, $pass;
public $pdo;
public function __construct($host, $user, $pass) {
$this->host = $host;
$this->user = $user;
$this->pass = $pass;
$this->connect();
}
private function connect() {
$this->pdo = new PDO("mysql:host={$this->host}", $this->user, $this->pass);
}
public function __sleep() {
return ['host', 'user', 'pass']; // 不序列化 $pdo(资源不可序列化)
}
public function __wakeup() {
$this->connect(); // 重建连接
}
}
⚠️ 注意事项
-
Serializable是更底层、更自由的控制方式,适合加密、版本兼容、跳过敏感字段等高级场景 -
__sleep()/__wakeup()更轻量,适合常规资源清理与重建,但无法改变序列化格式或绕过类型限制 -
private/protected属性在__sleep()中需按带前缀的完整名称写(如"\0*\0prop"),而Serializable中由你完全掌控数据结构 - PHP 8.1+ 已标记
Serializable为废弃(但尚未移除),官方推荐未来转向__serialize()/__unserialize()(PHP 7.4+ 引入的新魔术方法,优先级高于__sleep,低于Serializable)
? 执行优先级(从高到低)
-
Serializable::serialize()/unserialize()→ 最高,一旦实现就全程接管 -
__serialize()/__unserialize()→ PHP 7.4+ 新机制,若存在且类未实现Serializable,则使用它 -
__sleep()/__wakeup()→ 兜底方案,仅当以上两者都不存在时启用
不复杂但容易忽略。
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











