2010-08-27 37 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