我有一个复杂的嵌套对象层次结构,所有子对象(存储在父类中的对象数组)包含一个链接回其父级的属性:相当简单和直接,没有实际问题。如果我对层次结构中的任何对象执行var_dump,我将在转储中获得递归引用,正如我所期望的那样。
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_dump时,我得到一个“致命错误:嵌套级别太深 - 递归依赖?”。
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()除外。我已经尝试创建一个更简单的例子来演示这个问题,这样我就可以在提出这个问题时提供一个例子;但是在短期测试中无法复制它,只能在我更复杂的代码中复制它。
我知道解决方案是重构关系,以便我的_children_2数组的SECONDGEN_2对象保存在相应的SECONDGEN_1父级中,使父关系“正确”......我已经开始这样做了。 但是,我对错误很感兴趣,并想知道是否有其他人遇到过它(以及你自己如何处理它)。
答案 0 :(得分:71)
==
而不是===
如果需要比较实际对象实例,请始终使用严格比较运算符===
,因为它仅比较对象是否引用同一类的同一实例。
简短说明:
如果使用$object == $objectToCompareWith
比较对象,PHP会将第一个对象的每个属性和值与第二个对象进行比较。这种比较是对象的递归,这些对象是被比较对象的属性。
这意味着如果两个对象共享一个以对象作为其值的属性,PHP会对这些属性对象进行相同的==
比较。现在,只要这些属性对象是递归的(例如自引用对象),比较就会向下递归,直到达到最大嵌套级别。
正如Josh Stuart和mazatwork的评论中所述,通过将in_array()
参数设置为array_search()
,使用$strict
和true
等数组函数时可以强制进行严格比较}。
Richard Lord: "Nesting level too deep – recursive dependency?"
答案 1 :(得分:10)
在自引用代码中看起来像PHP限制,并尝试使用print_r
,var_dump
,var_export
显示它,或使用in_array
搜索它。基本上,如果对象被引用,那么这些函数无法知道在何处停止递归。
根据this bug report,reproduce this的最简单方法是:
$outText = var_export( $GLOBALS, true );
print_r($outText) ;
其他错误报告mention也是如此,还有一些测试用例。我会说,如果这只是在var_dump
中触发,你不应该太担心它。如果这是出于调试目的,我肯定是第二个Wrikken关于xdebug的建议。
答案 2 :(得分:3)
有时(但很少,因为这种争用的有效性有限)会发生这种情况,并且只要你的代码正常工作,我就不会过多考虑var_dump
(调试工具,不是生产一个)无法应付它。但是,如果您仍然需要 var_dump
才能工作,我可以衷心地推荐运行xdebug,您可以在其中设置var_dump
将显示的最大深度,最大长度为字符串转储和最大数量的子项。
答案 3 :(得分:1)
我遇到了与你相同的错误,但情况完全不同。我发布了答案,以防其他人像我一样来到这里。
如果你正在尝试使用一系列对象进行自定义排序(usort),这就是我必须做的事情:
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
偶尔会返回一个对象而不是一个数字。一旦我确定它总是返回一个数字,那么错误消失了。
答案 4 :(得分:0)
您可以使用魔术方法__toString来定义字符串的自定义转换。在实现__toString时,查看您的对象并避免过于递归,并且一切都应该没问题。永远不要忘记并且不小心调用var_dump,var_export,print_r等。
一旦定义了__toString方法,下面的工作就很好了:
echo $ yourObjectHere;
这是我目前的解决方案,效果很好,但我仍然希望保护我不要忘记不调用var_dump,var_export和print_r。
答案 5 :(得分:0)
也许这有助于某人。
对我来说,解决方案是在php.ini中引发pcre.recursion_limit
。但是,当您阅读其他答案时,这更像是一种临时解决方法,因为问题很可能在您自己的代码中。