Поддержание объектных отношений с помощью сериализации PHP

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

6
задан hakre 23 November 2012 в 00:27
поделиться