PHP序列化引用自身的类

时间:2018-01-05 00:00:18

标签: php serialization

给出一些背景;在添加Serializable接口之前,此过程正在运行。 TestAction2在反序列化后没有保留对自身的引用;我尝试将Serializable添加到Action类并告诉它序列化$parent,但仍然没有区别。尽管如此,它正确地将$method字段反序列化。

Action在引用它($parent)的类上进行序列化时序列化class B字段中的引用,但在引用自身时不序列化A。在类BAction而不是class A implements Serializable { private static $label; public function serialize() { return serialize(self::$label); } public function unserialize($serialized) { self::$label = unserialize($serialized); } } class B extends A { private $actions; public function serialize() { return serialize([ 'actions' => $this->actions, 'parent' => parent::serialize()]); } public function unserialize($serialized) { $data = unserialize($serialized); $this->actions = $data['actions']; parent::unserialize($data['parent']); } public function addAction($anAction) { $this->actions[] = $anAction; } public function process() { $this->addAction(new TestAction1($this, 'test1')); // WORKS FINE $this->addAction(new TestAction2($this, 'test2')); // WORKS NOT! } } class Action { private $parent; private $method; public function __construct($cParent, $sMethod) { $this->parent = $cParent; } } class TestAction1 extends Action { public function __construct($cParent, $sMethod) { parent::__construct($cParent, $sMethod); } } class TestAction2 extends Action { private $maybeNeedLater; public function __construct($cParent, $sMethod) { $this->maybeNeedLater = $cParent; parent::__construct($this, $sMethod); // pass $this instead } } $testThis = new B(); $testThis->process(); $serialized = serialize($testThis); $testThis = unserialize($serialized); 类本身上发生序列化的事情。

Action

TestAction2$parent$actions

$testThis字段中将显示空((()(字段

1 个答案:

答案 0 :(得分:1)

你的两个不同的Action类有点红鲱鱼,因为它们不是问题所在。 Test2恰好使用$ testThis以外的引用;许多其他参考也是错误的。

真正的问题是A / B类中的序列化顺序与反序列化的顺序不同。在序列化期间,PHP使用r(或R)和数字编码引用(r和R在许多方面是不同的,但差异只会分散计数问题)。在你的例子中,$ needThis可以用r:1;,A :: label用r:2;引用,actions数组用r:3;等等。 $ this对TestAction2对象的引用是r:8; (当你回复$ serialized时,你会看到这个。)

当你在unserialize函数中调用unserialize时,没有A :: label(还)。因为所有大于1的数字都会被一个数字关闭。 R:8;现在指向maybeNeedLater中的任何内容。

现在事情有点复杂,因为PHP通常不会创建这样的字符串。在PHP5中,它似乎创建了一些打印为NULL的错误。在PHP7中,parent实际上是对$ needThis的引用。

幸运的是,有几种简单的方法可以解决这个问题:

选项1:

使用不同的格式对父类进行编码:

class A implements Serializable {
  private static $label;

  public function serialize() {
    return json_encode(self::$label);
  }
  public function unserialize($serialized) {
    self::$label = json_decode($serialized);
  }
}

选项2:

在子类中使用双序列化并确保订单适合:

class B extends A {
private $actions;

public function serialize() {
    return json_encode([
            'actions' => serialize($this->actions),
            'parent' => parent::serialize()]);
}
public function unserialize($serialized) {
    $data = json_decode($serialized, true);
    $this->actions = unserialize($data['actions']);
    parent::unserialize($data['parent']);
}
...