2010-08-27 40 views
5

我一直在使用SplObjectStorage,像上面的例子中實現一個簡單的複合模式:錯誤序列化對象樹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); 
    } 
} 

每當我試圖序列組合對象,PHP 5.3.2拋出我Segmentation Fault。 只有當我將任意數量的節點添加到對象時,纔會發生這種情況。

這是有問題的代碼:

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

雖然這一個工程:

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

另外,如果我實現與陣列)的複合模式(而不是SplObjectStorage,一切運行正常了。

我做錯了什麼?

回答

8

通過設置父項,您有一個循環參考。 PHP會嘗試序列化組合,所有的節點和節點都會嘗試序列化組合..繁榮!

您可以使用神奇的__sleep and __wakeup()方法在序列化時刪除(或做任何事情)父引用。在

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

...和綜合的方法__wakeup通過調用的setParent($本)恢復父參考:

編輯:

看看這些添加到Composite修復該問題每個子元素。 – VolkerK 2010-08-27 11:58:22

+1

謝謝!我認爲serialize()會足夠聰明來處理引用,但它不會。我已經通過在兩個類中實現Serializable接口來解決它。 – xPheRe 2010-08-27 12:43:25