Фатальная ошибка: слишком глубокий уровень вложенности - рекурсивная зависимость?
у меня есть сложная иерархия вложенных объектов, со всеми дочерними объектами (хранится массив объектов в родительском классе), содержащий свойство, связанное с их родителем: довольно простой и простой, без реальных проблем. Если я сделаю 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 ответов
похоже на ограничение PHP в коде с самостоятельной ссылкой и пытается отобразить его с помощью print_r
, var_dump
, var_export
, или поиск через него с in_array
. В принципе, эти функции не могут знать, где прекратить рекурсию, если на объект ссылаются cirularly.
по данным этот отчет об ошибке самый простой способ воспроизвести эту - это:
$outText = var_export( $GLOBALS, true );
print_r($outText) ;
другие сообщения об ошибках отметить это тоже, с некоторыми другими тестовыми случаями. Я бы сказал, что если это срабатывает только в var_dump
вы не должны слишком беспокоиться об этом. Я определенно поддерживаю предложение Wrikken о xdebug, если это для целей отладки.
это также возникает, если вы сравниваете рекурсивные объекты с помощью ==
вместо ===
Если вам нужно сравнить фактические экземпляры объекта всегда используйте строгий оператор сравнения ===
как он сравнивает, только если объекты ссылаются на один и тот же экземпляр того же класса.
краткое описание:
если вы сравниваете объекты с помощью $object == $objectToCompareWith
, PHP сравнивает каждый атрибут и значение первого объекта со вторым. Этот сравнение рекурсивно по объектам, которые являются свойствами сравниваемых объектов.
это означает, что если оба объекта разделяют атрибут с объектом в качестве его значения, PHP делает то же самое ==
сравнение между этими объектами атрибутов. Теперь, как только один из этих объектов атрибутов рекурсивен (например, объект с собственной ссылкой), сравнение рекурсирует вниз, пока не будет достигнут максимальный уровень вложенности.
как указано в комментариях Джоша Стюарта и mazatwork, строгое сравнение может быть принудительным при использовании функций массива, таких как in_array()
и array_search()
установив их до true
.
Ричард Лорд: "уровень вложенности слишком глубокая рекурсивная зависимость?"
иногда (но редко, так как для таких контрастов используются ограниченные допустимые значения) это происходит, и пока ваш код работает правильно, я бы не задумывался, что var_dump
(инструмент отладки, а не производственный) не может справиться с этим. Однако, если вы все еще нужно var_dump
для работы я могу сердечно рекомендовать запуск xdebug, в котором вы можете установить максимальную глубину var_dump
покажет, максимальная длина дампа строки и максимальное количество детей.
Я получал ту же ошибку, что и вы, но в совершенно другом сценарии. Я отправляю ответ на случай, если кто-то еще попадет сюда так же, как и я.
в случае, если вы пытаетесь выполнить пользовательскую сортировку (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
иногда возвращал объект вместо числа. Как только я убедился, что он всегда возвращает номер, тогда ошибка пошла прочь.
вы можете использовать магический метод __toString для определения пользовательского преобразования в строку. Просмотрите свой объект и избегайте слишком глубоких рекурсий при реализации __toString, и все должно быть хорошо. Просто никогда не забывайте и случайно вызывайте var_dump, var_export, print_r и т. д.
после того, как метод _ _ toString был определен, хорошо работает следующее:
echo $yourObjectHere;
Это мое текущее решение, которое работает хорошо, но я все равно хотел бы что-то защитить меня от забывания не вызывать var_dump, var_export и print_r.
возможно, это кому-то помогает.
для меня решением было поднять pcre.recursion_limit
в php.ini. Однако это скорее временное решение, когда вы читаете другие ответы, поскольку проблема, скорее всего, лежит внутри вашего собственного кода.