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

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

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

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


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