Я столкнулся с довольно сложной проблемой, связанной с объектами, реализующими интерфейс Serializable
.Давайте рассмотрим пример:
class A {
public $b;
}
class B {
public $a;
}
$a = new A;
$b = new B;
$a->b = $b;
$b->a = $a;
echo serialize($a); // O:1:"A":1:{s:1:"b";O:1:"B":1:{s:1:"a";r:1;}}
echo serialize($b); // O:1:"B":1:{s:1:"a";O:1:"A":1:{s:1:"b";r:1;}}
$a = unserialize(serialize($a));
var_export($a === $a->b->a); // true
В этом примере мы можем видеть, что при использовании встроенной функции сериализации PHP (независимо от того, используем ли мы функцию __sleep()
), перекрестные ссылки между A
& B
сохраняются (r:1;
).
Однако, если мы хотим обеспечить использование интерфейса Serializable, возникает проблема:
class A implements Serializable {
public $b;
public function serialize() { return serialize($this->b); }
public function unserialize($s) { $this->b = unserialize($s); }
}
class B implements Serializable {
public $a;
public function serialize() { return serialize($this->a); }
public function unserialize($s) { $this->a = unserialize($s); }
}
$a = new A;
$b = new B;
$a->b = $b;
$b->a = $a;
echo serialize($a); // infinite loop crashes PHP
Поскольку сериализация каждого объектауправляется независимо, не существует глобального способа увидеть, был ли объект уже сериализован, создать ссылку на него.Затем serialize()
функции вызываются в бесконечном цикле.
Есть ли хороший обходной путь для этой проблемы?Шаблон для использования в serialize()
функциях?