代码之家  ›  专栏  ›  技术社区  ›  Mark Baker

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

  •  22
  • Mark Baker  · 技术社区  · 14 年前

    我有一个复杂的嵌套对象层次结构,所有子对象(在父类中存储了一个对象数组)都包含一个链接回其父类的属性:相当简单和简单,没有实际问题。如果我对层次结构中的任何对象执行var_转储,我将在转储中得到一个递归引用,正如我所期望的那样。

    FIRSTGEN 
       _children array of objects of type SECONDGEN
          SECONDGEN #1
             _parent object of type FIRSTGEN
             _children array of objects of type THIRDGEN
                THIRDGEN #1
                   _parent object of type SECONDGEN
                THIRDGEN #2
                   _parent object of type SECONDGEN
          SECONDGEN #2
             _parent object of type FIRSTGEN
             _children array of objects of type THIRDGEN
                THIRDGEN #3
                   _parent object of type SECONDGEN
    

    我最近在这个层次结构中添加了一些新的元素,它们不遵循完全相同的模式。它们存储在顶级父级中的对象数组中,但包含一个将它们链接回的属性,而不是链接到其父级,而是链接到兄弟级。当我现在执行var_转储时,会得到一个“致命错误:嵌套级别太深-递归依赖?”.

    FIRSTGEN 
       _children_1 array of objects of type SECONDGEN_1
          SECONDGEN_1 #1
             _parent object of type FIRSTGEN
             _children array of objects of type THIRDGEN
                THIRDGEN #1
                   _parent object of type SECONDGEN_1
                THIRDGEN #2
                   _parent object of type SECONDGEN_1
          SECONDGEN_1 #2
             _parent object of type FIRSTGEN
             _children array of objects of type THIRDGEN
                THIRDGEN #3
                   _parent object of type SECONDGEN_1
       _children_2 array of objects of type SECONDGEN_2
          SECONDGEN_2 #1
             _parent object of type SECONDGEN_1
    

    除了var_dump()之外,代码中的其他所有内容都正常工作。我试图创建一个更简单的例子来演示这个问题,这样我可以在问这个问题时提供一个例子;但是我还没有能够在一个简短的测试中复制它,只是在我更复杂的代码中。

    我知道解决方案是重构关系,以便我的secondgen_2对象数组secondgen_2子数组保存在适当的secondgen_1父数组中,使父关系“正确”…我已经开始这样做了。 然而,我对这个错误很感兴趣,想知道是否还有其他人遇到过这个错误(以及您自己是如何处理的)。

    6 回复  |  直到 7 年前
        1
  •  10
  •   Fanis Hatzidakis    14 年前

    在自引用代码中看起来像是一个PHP限制,并试图用 print_r , var_dump , var_export 或者用 in_array . 基本上,如果一个对象被循环引用,那么这些函数就无法知道在哪里停止递归。

    根据 this bug report 最简单的方法 reproduce this 是:

    $outText = var_export( $GLOBALS, true );
    print_r($outText) ;
    

    其他错误报告 mention 还有一些测试案例。我想说如果这只是 瓦尔转储 你不应该为此担心太多。如果这是出于调试目的,我肯定会附和Wrikken关于xdebug的建议。

        2
  •  71
  •   flu    8 年前

    如果使用 == 而不是 ===

    如果需要比较实际的对象实例 始终使用严格比较运算符 = = 因为它只在对象引用同一类的同一实例时进行比较。

    简短说明:

    如果使用比较对象 $object == $objectToCompareWith ,php正在比较第一个对象和第二个对象的每个属性和值。这个比较是对对象的递归比较,对象是被比较对象的属性。

    这意味着,如果两个对象共享一个属性,并将一个对象作为其值,则php会执行相同的操作 = 这些属性对象之间的比较。现在,一旦这些属性对象递归(例如自引用对象),比较也会向下循环,直到达到最大嵌套级别。

    如josh stuart和mazatwork的评论所述,当使用类似 in_array() array_search() 通过设置各自的 $strict 参数到 true .

    Richard Lord: "Nesting level too deep – recursive dependency?"

    PHP Manual: "Comparing Objects"

        3
  •  3
  •   Wrikken    14 年前

    有时(但很少,因为对此类争议的有效性有限),这种情况会发生,只要您的代码正常工作,我就不会认为 var_dump (调试工具,而不是生产工具)无法处理它。但是,如果你仍然 需要 瓦尔转储 为了工作,我衷心建议您运行xdebug,您可以在其中设置 瓦尔转储 将显示字符串转储的最大长度和子级的最大数量。

        4
  •  1
  •   Jacksonkr    8 年前

    我和你的错误是一样的,但情况完全不同。我把答案贴出来,以防其他人和我一样来到这里。

    如果您尝试自定义排序 (使用) 对于一组对象,我需要做的是:

    function cmp($a, $b) {
        if($a->num_estimates == $b->num_estimates) return 0;
    
        return($a->num_estimates < $b->num_estimates) ? -1 : 1;
    }
    $c = usort(Company::$companies, "cmp");
    

    结果是 $object->num_estimates 偶尔返回一个对象而不是数字。一旦我确定它总是返回一个数字,那么错误就消失了。

        5
  •  0
  •   Paul    13 年前

    你可以使用魔法方法 __toString 定义到字符串的自定义转换。查看对象,避免在实现uu-ToString时过于深入地执行递归,一切都应该很好。永远不要忘记并意外地调用var_dump、var_export、print_等。

    一旦定义了uu-ToString方法,以下方法就可以很好地工作:

    回音$yourobjecthere;

    这是我目前的解决方案,它运行得很好,但我仍然希望有一些东西可以保护我不忘记不要调用var_dump、var_export和print_r。

        6
  •  0
  •   pdu    7 年前

    也许这对某人有帮助。

    对我来说,解决办法是提高 pcre.recursion_limit 在PHP.ini中。不过,当您阅读其他答案时,这更像是一个临时的解决方法,因为问题很可能就在您自己的代码中。