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