2010-08-27 4 views
5

ho implementato un semplice composite utilizzando SplObjectStorage, come nell'esempio precedente:Errore serializzazione di un albero di oggetto 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); 
    } 
} 

Ogni volta che provo per serializzare un oggetto composito, PHP 5.3.2 mi butta un Segmentation Fault. Questo succede solo quando aggiungo qualsiasi numero di nodi di qualsiasi tipo all'oggetto.

Questo è il codice incriminato:

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

Anche se questo funziona:

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

Inoltre, se a implementare il modello composito con array() al posto di SplObjectStorage, tutte le piste troppo male.

Cosa sto facendo male?

risposta

8

Impostando il padre, si dispone di un riferimento circolare. PHP proverà a serializzare il composito, tutti i suoi nodi e i nodi a loro volta cercheranno di serializzare il boom composito ..!

È possibile utilizzare i metodi magici __sleep and __wakeup() per rimuovere (o fare qualsiasi cosa per) il riferimento principale durante la serializzazione.

EDIT:

Vedere se l'aggiunta di questi per Composite corregge il 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

... e il metodo __wakeup in composito per ripristinare il genitore di riferimento chiamando setParent ($ this) su ogni elemento figlio. – VolkerK

+1

Grazie! Pensavo che serialize() sarebbe stato abbastanza intelligente da gestire i riferimenti, ma non è così. L'ho risolto implementando l'interfaccia Serializable in entrambe le classi. – xPheRe