带有循环引用的对象的in_array

时间:2011-12-10 21:27:25

标签: php arrays object recursion circular-reference

我正在构建一个对象数组。我需要这个数组只包含一个给定对象的实例,对同一个对象的多个引用应该抛出异常。我正在使用以下代码来实现此目的:

public function addField ($name, iface\Node $field)
{
    // Prevent the same field being added multiple times
    if (!in_array ($field, $this -> fields))
    {
        $this -> fields [$name] = $field;
        $field -> setParent ($this);
    }
    else
    {
        throw new \InvalidArgumentException ('This field cannot be added to this group');
    }
    return ($this);
}

当我开始实现实现Node接口的对象时,这开始导致问题,因为它们可以包含循环引用(它们包含子节点的集合,每个子节点都包含对其父节点的引用)。尝试添加字段可能会导致生成以下错误:

  

PHP致命错误:嵌套级别太深 - 递归依赖?

我怀疑PHP正在尝试遍历整个对象数组,而不是仅仅比较对象引用以查看它们是否具有相同的值,因此指向同一个对象。

我需要in_array做的只是将它存储的对象引用与字段的对象引用进行比较。这将阻止它尝试遍历整个对象树并遇到递归问题。

有没有办法做到这一点?

2 个答案:

答案 0 :(得分:18)

事实证明,答案非常简单。看起来默认情况下,在测试针的草堆时,in_array会进行非严格比较(相当于==操作)。这意味着它检查所有属性是否相等,这意味着它开始遍历对象图,如果您在该图中有循环引用,则可能会让您遇到麻烦。

in_array函数有一个严格模式,但据我所知,这相当于===操作。这似乎导致它检查引用以查看它们是否指向同一对象而不是比较所有属性。

只需将代码更改为:

if (!in_array ($field, $this -> fields, true))

使该方法的行为与我希望它在没有触发递归错误的情况下表现一样。

我不得不说,我有点惊讶PHP默认情况下不执行此模式。另一方面,我想我真的不应该对PHP的弱打字再次引起我的问​​题感到惊讶。 :)

答案 1 :(得分:1)

我只会使用SplObjectStoragespl_object_hash

你是对的,当php比较事物时,它会以递归的方式遍历结构(数组也是如此)。