Неустранимая ошибка: уровень вложенности слишком глубокий - рекурсивная зависимость? - PullRequest
22 голосов
/ 01 октября 2010

У меня сложная иерархия вложенных объектов со всеми дочерними объектами (хранится массив объектов в родительском классе), содержащим свойство, ссылающееся на их родительский объект: довольно простое и понятное, без реальных проблем.Если я сделаю 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 родитель, что делает родительские отношения "правильными" ... Я уже начал это делать.Однако я заинтригован этой ошибкой и удивился, если кто-то еще сталкивался с ней (и как вы справились с ней самостоятельно).

Ответы [ 6 ]

74 голосов
/ 30 сентября 2013

Это также возникает, если вы сравниваете рекурсивные объекты, используя == вместо ===

Если вам нужно сравнить фактические экземпляры объекта , всегда используйте оператор строгого сравнения ===, поскольку он сравнивает только, если объекты ссылаются на один и тот же экземпляр того же класса.

Краткое объяснение:

Если вы сравниваете объекты, используя $object == $objectToCompareWith, PHP сравнивает каждый атрибут и значение первого объекта со вторым. Это сравнение рекурсивно по объектам, которые являются свойствами сравниваемых объектов.

Это означает, что если оба объекта совместно используют атрибут с объектом в качестве его значения, PHP делает то же самое == сравнение между этими объектами атрибута. Теперь, как только один из этих атрибутных объектов становится рекурсивным (например, самоссылающийся объект), сравнение повторяется и до достижения максимального уровня вложенности.

Как указано в комментариях Джоша Стюарта и mazatwork, строгое сравнение можно принудительно использовать при использовании таких функций массива, как in_array() и array_search(), установив для их соответствующего параметра $strict значение true.

Ричард Лорд: «Уровень вложенности слишком глубокий - рекурсивная зависимость?»

Руководство по PHP: "Сравнение объектов"

10 голосов
/ 01 октября 2010

Похоже на ограничение PHP в самоссылающемся коде и попытке отобразить его с помощью print_r, var_dump, var_export или выполнить поиск по нему с помощью in_array. По сути, эти функции не могут знать, где прекратить повторение, если на объект ссылаются по кругу.

Согласно этому сообщению об ошибке самый простой способ воспроизвести это :

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

Другие сообщения об ошибках также упоминается , с некоторыми другими тестами. Я бы сказал, что если это сработает только в var_dump, вам не стоит об этом слишком беспокоиться. Я определенно поддерживаю предложение Вриккена о xdebug, если это для целей отладки.

3 голосов
/ 01 октября 2010

Иногда (но редко, поскольку для таких контрастек используются ограниченные допустимые значения), и до тех пор, пока ваш код работает должным образом, я бы не стал думать, что var_dump (инструмент отладки, а непроизводство одно) не может с этим справиться.Однако, если вам все еще нужно var_dump для работы, я могу от всей души рекомендовать запустить xdebug, в котором вы можете установить максимальную глубину, которую покажет var_dump, максимальную длину дампа строки иМаксимальное количество детей.

1 голос
/ 30 октября 2015

Я получаю ту же ошибку, что и вы, но в совершенно другом сценарии. Я отправляю ответ на тот случай, если кто-нибудь еще придет сюда так же, как и я.

В случае, если вы пытаетесь выполнить пользовательскую сортировку (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 иногда возвращал объект вместо числа. Как только я убедился, что он всегда возвращает число, ошибка исчезла.

0 голосов
/ 17 августа 2017

Может быть, это кому-нибудь поможет.

Для меня решение было поднять pcre.recursion_limit в php.ini.Это скорее временный обходной путь, когда вы читаете другие ответы, поскольку проблема, скорее всего, заключается в вашем собственном коде.

0 голосов
/ 14 марта 2011

Вы можете использовать магический метод __ toString , чтобы определить пользовательское преобразование в строку. Просматривайте свой объект и избегайте слишком глубоких рекурсий при реализации __toString, и все должно быть хорошо. Просто никогда не забывайте и случайно вызывайте var_dump, var_export, print_r и т. Д.

Как только метод __toString был определен, хорошо работает следующее:

echo $ yourObjectHere;

Это мое текущее решение, которое работает хорошо, но я все же хотел бы, чтобы что-то защитило меня от забывания не вызывать var_dump, var_export и print_r.

...