Подтвердить что ты не робот

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

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

4b9b3361

Ответ 1

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

В соответствии с этот отчет об ошибках самый простой способ воспроизвести этот есть:

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

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

Ответ 2

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

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

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

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

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

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

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

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

Ответ 3

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

Ответ 4

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

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

Ответ 5

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

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

echo $yourObjectHere;

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

Ответ 6

Может быть, это помогает кому-то.

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