在类中使用 behaviors 时,如何避免序列化失败

现象

有时候在类中使用了 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 即可。

你可能感兴趣的:(在类中使用 behaviors 时,如何避免序列化失败)