Я столкнулся с довольно сложной проблемой, связанной с объектами, реализующими интерфейс 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 ()
?