【问题标题】:Error serializing an object tree with SplObjectStorage使用 SplObjectStorage 序列化对象树时出错
【发布时间】:2011-04-04 18:18:30
【问题描述】:

我已经使用 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);
    }
}

每当我尝试序列化 Composite 对象时,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);

另外,如果我使用 array() 而不是 SplObjectStorage 来实现 Composite 模式,也可以正常运行。

我做错了什么?

【问题讨论】:

    标签: php serialization segmentation-fault composite spl


    【解决方案1】:

    通过设置Parent,你有一个循环引用。 PHP 将尝试序列化复合,它的所有节点和节点依次尝试序列化复合..繁荣!

    您可以使用神奇的__sleep and __wakeup() 方法在序列化时删除(或对父引用执行任何操作)。

    编辑:

    查看将这些添加到 Composite 是否可以解决问题:

    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;
    }
    

    【讨论】:

    • ...和 ​​Composite 中的 __wakeup 方法通过在每个子元素上调用 setParent($this) 来恢复父引用。
    • 谢谢!我认为 serialize() 足够聪明来处理引用,但事实并非如此。我通过在两个类中实现 Serializable 接口解决了这个问题。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-01-09
    • 2014-06-22
    • 2019-01-08
    相关资源
    最近更新 更多