2010-08-27 12 views
5

he implementado un patrón Composite simple usando SplObjectStorage, como el ejemplo anterior:Error serialización de un árbol de objetos con SplObjectStorage

class Node 
{ 
    private $parent = null; 

    public function setParent(Composite $parent) 
    { 
     $this->parent = $parent; 
    } 
} 

class Composite extends Node 
{ 
    private $children; 

    public function __construct() 
    { 
     $this->children = new SplObjectStorage; 
    } 

    public function add(Node $node) 
    { 
     $this->children->attach($node); 
     $node->setParent($this); 
    } 
} 

Siempre que trato de serializar un objeto compuesto, PHP 5.3.2 me lanza una Segmentation Fault. Esto solo ocurre cuando agrego cualquier cantidad de nodos de cualquier tipo al objeto.

Este es el código erróneo:

$node = new Node; 
$composite = new Composite; 
$composite->add($node); 
echo serialize($composite); 

Aunque éste funciona:

$node = new Node; 
$composite = new Composite; 
echo serialize($composite); 

Además, si puedo implementar el patrón Composite con array() en lugar de SplObjectStorage, todas las carreras bien también.

¿Qué estoy haciendo mal?

Respuesta

8

Al configurar Parent, tiene una referencia circular. PHP tratará de serializar el compuesto, todos sus nodos y los nodos a su vez intentarán serializar el compuesto ... ¡auge!

Puede utilizar los métodos mágicos __sleep and __wakeup() para eliminar (o hacer lo que sea con) la referencia principal al serializar.

EDIT:

A ver si la adición de estos a Composite corrige el problema:

public function __sleep() 
{ 
    $this->children = iterator_to_array($this->children); 
    return array('parent', 'children'); 
} 
public function __wakeup() 
{ 
    $storage = new SplObjectStorage; 
    array_map(array($storage, 'attach'), $this->children); 
    $this->children = $storage; 
} 
+1

... y el método de __wakeup compuesto para restaurar la referencia de los padres llamando setParent ($ this) en cada elemento hijo. – VolkerK

+1

Gracias! Pensé que serialize() sería lo suficientemente inteligente como para tratar con referencias, pero no lo es. Lo resolví implementando la interfaz Serializable en ambas clases. – xPheRe

Cuestiones relacionadas