使用循环引用的对象上的In_array


in_array on objects with circular references

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

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做的就是比较它存储的对象引用和field的对象引用。这将防止它试图遍历整个对象树并遇到递归问题。

有办法做到这一点吗?

答案其实非常简单。默认情况下,in_array在测试haystack中的指针时执行非严格比较(相当于==操作)。这意味着它检查所有属性是否相等,这意味着它开始遍历对象图,如果你在图中有循环引用,这可能会给你带来麻烦。

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

只需将代码更改为:

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

使方法按照我希望的方式运行,而不会触发递归错误。

我不得不说,我有点惊讶PHP没有默认使用这种模式。另一方面,我想我真的不应该对PHP的弱类型再次给我带来问题感到惊讶。:)

我只使用SplObjectStoragespl_object_hash

你是对的,当php比较事物时,它会递归地遍历结构(数组也是)