PHP中Property hook与__sleep结合序列化时出现属性不存在警告问题
问题分析
这不是PHP Bug,是对**PHP 8.1+引入的带get/set的合成属性(Property hook)**与__sleep()工作机制的理解偏差导致的:
- 带get/set的
$bar属于合成属性:它并非实际存储在对象的属性集合中,只是语法糖,底层通过类似魔术方法的逻辑实现读写,不会被PHP判定为“真实成员变量”。 get_object_vars($this)会返回合成属性名称:该函数会将可访问的合成属性纳入结果,但serialize()处理__sleep()返回的列表时,只会检查对象中真实存在的成员变量,因此出现“返回了bar但不存在”的警告。
解决方案
方案1:手动指定序列化的真实属性
不要依赖get_object_vars()自动生成返回列表,直接指定需要序列化的真实成员变量即可:
class A { private array $foo = ['baz' => 10]; public int $bar { get => $this->foo['baz']; set { $this->foo['baz'] = $value; } } public function __sleep() { // 仅返回真实存在的成员变量 return ['foo']; } } $a = new A; $a->bar = 20; var_dump(unserialize(serialize($a)));
序列化仅处理$foo,反序列化后$bar依然可通过钩子正常读取$foo['baz']的值,同时避免警告。
方案2:通过反射动态过滤合成属性
若类中属性较多,可通过反射自动区分真实属性与合成属性:
class A { private array $foo = ['baz' => 10]; public int $bar { get => $this->foo['baz']; set { $this->foo['baz'] = $value; } } public function __sleep() { $reflection = new ReflectionClass($this); // 获取类定义中声明的真实属性名称 $realProperties = array_map(fn(ReflectionProperty $prop) => $prop->getName(), $reflection->getProperties()); return $realProperties; } }
内容的提问来源于stack exchange,提问作者Eran Machiels
相关产品推荐
相关产品推荐

