【问题标题】:in_array on objects with circular references具有循环引用的对象上的 in_array
【发布时间】:2012-01-17 14:27:44
【问题描述】:

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

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 做的只是将它存储的对象引用与字段的对象引用进行比较。这将防止它尝试遍历整个对象树并遇到递归问题。

有没有办法做到这一点?

【问题讨论】:

  • 尝试在您的对象上覆盖__equals 以实现更适合您的目的的相等检查方法。

标签: php arrays object recursion circular-reference


【解决方案1】:

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

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

只需将代码更改为:

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

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

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

【讨论】:

    【解决方案2】:

    我只会使用SplObjectStoragespl_object_hash

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

    【讨论】:

    • @mifki 你可以做 type strict === 比较。它将比较对象的点。
    • 感谢您的回复,但我想我已经找到了解决方案。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-04-19
    • 2017-08-04
    • 2012-02-10
    • 1970-01-01
    • 2011-06-19
    • 1970-01-01
    相关资源
    最近更新 更多