现象
有时候在类中使用了 TimestampBehavior 或其他 AttributeBehavior,突然缓存就不能用了,写入缓存时抛出异常:
Exception: Serialization of 'Closure' is not allowed in ...
这可能是因为在将数据写入缓存前,要用到 PHP 的 serialize() 函数对数据进行序列化,从而导致异常。
分析
以 Yii 框架为例,定义一个 Team 对象,并使用 AttributeBehavior 自动填充 name 字段。
class Team extends ActiveRecord{
public function behaviors(){
return [
[
'class' => AttributeBehavior::className(),
'attributes' => [
ActiveRecord::EVENT_BEFORE_INSERT => 'name',
],
// 填充时使用一个 closure,仅为举例
'value' => function ($event) {
return '爵士队';
},
],
];
}
}
当序列化 Team 类时,PHP 会对它的所有属性执行 serialize,并一层层嵌套执行下去。
由于 Team 使用了 AttributeBehavior(或者它的派生类 TimestampBehavior),就会在它的 _behaviors 属性(是个数组)中添加实例,当一层层进行序列化时,最终也要对 AttributeBehavior.value 进行序列化时,就会报异常。
解决方法
由于 behavior 一般不会用在序列化的场景,所以可以重载 __sleep() 函数,避免 Behavior 实例被序列化:
class MyAttributeBehavior extends AttributeBehavior{
public function __sleep(){
return [];
}
}
然后在 Team 类的 behaviors() 中,使用 MyAttributeBehavior 来替换 AttributeBehavior 即可。
网友评论