Решение для «Неустранимая ошибка: достигнут максимальный уровень вложенности функции« 100 », прерывание!» в PHP

138

Я создал функцию, которая находит все URL-адреса в HTML-файле и повторяет один и тот же процесс для каждого HTML-содержимого, связанного с обнаруженными URL-адресами. Функция рекурсивная и может продолжаться бесконечно. Однако я наложил ограничение на рекурсию, установив глобальную переменную, которая заставляет рекурсию останавливаться после 100 рекурсий.

Тем не менее, php возвращает эту ошибку:

Неустранимая ошибка: достигнут максимальный уровень вложенности функции «100», прерывание! в D: \ wamp \ www \ crawler1 \ simplehtmldom_1_5 \ simple_html_dom.php в строке 1355

ОШИБКА

Я нашел решение здесь: увеличение лимита вызовов вложенных функций, но в моем случае это не работает.

Я цитирую один из ответов по ссылке, указанной выше. Пожалуйста, примите это во внимание.

«У вас установлены Zend, IonCube или xDebug? Если это так, то, вероятно, именно здесь вы и получаете эту ошибку.

Я столкнулся с этим несколько лет назад, и в итоге Zend установил этот предел, а не PHP. Конечно, его удаление> позволит вам пройти 100 итераций, но в итоге вы достигнете пределов памяти ».

Есть ли способ увеличить максимальный уровень вложенности функций в PHP?

Rafay
источник
2
Кроме того: PHP не имеет ограничений на количество вложенных вызовов функций, это должно быть расширение, которое вы используете, которое вызывает это.
Авель
@Abel Я уверен, что в моем коде нет ошибок. Есть статическая переменная, которая увеличивает свое значение на единицу при каждом рекурсивном вызове. Если эта переменная меньше 100, рекурсивные вызовы продолжаются, пока переменная не достигнет 100. Я хочу сказать, что переменная, достигающая 100, на самом деле является базовым случаем. Пока ошибка возникает до 100 рекурсий. И поскольку вы упомянули, что это может быть вызвано некоторым расширением, я хотел бы отметить, что я использую функции из simple_html_dom.php. Если у вас есть идеи о simple_html_dom.php, пожалуйста, помогите мне в этом. Пожалуйста, обратитесь к обновленному вопросу.
Рафай
7
Это ошибка от xdebug. На скриншоте видно, что вы используете xdebug. Вы можете отключить настройку здесь: xdebug.max_nesting_level или указать, насколько велик уровень вложенности.
хакре
3
если вы используете WAMP, обратите внимание, что отключение xdebug в php.ini не всегда работает; то же самое относится к расширению уровня разрешенной вложенности; ошибка предположение; РЕШЕНИЕ: зайдите на php.ini и закомментируйте php_xdebug - ???.
Dll

Ответы:

145

Увеличьте значение xdebug.max_nesting_levelв вашемphp.ini

Maxence
источник
6
@AL Вы редактируете свой файл php.ini и добавляете или редактируете строку xdebug.max_nesting_level в разделе XDebug.
Максенс
3
Однако, если это производственная среда, посмотрите принятый ответ, который должен отключить xdebug в этой среде.
zkent
3
Это решает симптом (на некоторое время), но не проблему.
Себастьян Мах
1
Это решение работало для меня, когда я использовал UFront для Haxe на MAMP.
доверенное лицо
4
на неограниченное время:xdebug.max_nesting_level = -1
Наби КАЗ
55

Простое решение решило мою проблему. Я только что прокомментировал эту строку:

zend_extension = "d:/wamp/bin/php/php5.3.8/zend_ext/php_xdebug-2.1.2-5.3-vc9.dll

в моем php.iniфайле. Это расширение ограничивало стек, 100поэтому я отключил его. Рекурсивная функция теперь работает как положено.

Rafay
источник
4
Итак, в конце концов это было расширение XDebug ... Полезно знать. Через два дня вы можете принять свой собственный ответ в качестве принятого, если хотите (и посмотрите на свои предыдущие вопросы, большинство пропустит принятый ответ).
Авель
61
Работа с чрезмерной рекурсией, безусловно, лучше, чем просто отключение мониторинга.
petesiss
7
Это неуклюжий подход. Приведенные выше ответы, в которых упоминается переменная для настройки максимальной глубины стека, являются лучшим подходом.
Аредридель
7
Вы не должны включать xdebug в производственной среде.
HarryFink
2
святое дерьмо. Я не могу перестать смеяться над выбранным решением. Так что мой компьютер не переставал шуметь, поэтому я нашел решение. Выключи это. :)
Кевин Ремисоски
44

Вместо того, чтобы использовать рекурсивные вызовы функций, работайте с моделью очереди, чтобы сгладить структуру.

$queue = array('http://example.com/first/url');
while (count($queue)) {
    $url = array_shift($queue);

    $queue = array_merge($queue, find_urls($url));
}

function find_urls($url)
{
    $urls = array();

    // Some logic filling the variable

    return $urls;
}

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

Луи-Филипп Юбердо
источник
5
С SPL вам не нужно заново изобретать очередь: php.net/manual/en/class.splqueue.php
Франческо
1
SPL Queue может обеспечить немного большую скорость, но мне нравится использовать массивы для самых простых задач. Push / Pop / Shift / Unshift все предоставляются.
Луи-Филипп Юбердо
1
Это правильный ответ. Избегайте изменения значений по умолчанию. Попробуйте оптимизировать свой код.
Джунаид Atique
41

Другое решение - добавить xdebug.max_nesting_level = 200в свой php.ini

Bacar ndiaye
источник
8
это также возможно сделать в php, например, в файле конфигурации вашего проекта. ini_set('xdebug.max_nesting_level', 200);
svassr
@htxryan Я не эксперт, но это связано с тем, что ваш стек вызовов слишком "глубокий" (слишком много функций вызывает другие функции). Типичный сценарий, в котором это происходит, с рекурсивной функцией. Параметр, скорее всего, позволяет избежать рекурсии «из-под контроля» из-за ошибки в коде.
Брайан
@svassr, возможно, вы захотите добавить этот совет в качестве отдельного ответа или добавить к уже существующему, он был полезен для меня, но почти пропустил его в комментариях
Брайан,
@Bryan только что добавил ответ
svassr
23

Вместо того, чтобы отключить xdebug, вы можете установить более высокий предел, как

xdebug.max_nesting_level = 500

shahinam
источник
@SebastianMach: и, что удивительно, спустя годы тоже. :) (Примерно четыре раза или около того. Люди не только не читают сейчас, они даже больше не прокручивают.)
Sz.
1
@Sz: Ух ты, какой взрыв из прошлого: P Удивительно шокирующий.
Себастьян Мах
18

Это также можно исправить прямо в php, например, в файле конфигурации вашего проекта.

ini_set('xdebug.max_nesting_level', 200);

svassr
источник
1
Спасибо, это прекрасно работает, так как мне не нужно беспокоиться об обновлении php.ini на всех моих устройствах разработки, я просто добавляю это в файл начальной загрузки моего приложения.
Брайан
13

Перейдите в файл конфигурации php.ini и измените следующую строку:

xdebug.max_nesting_level=100

что-то вроде:

xdebug.max_nesting_level=200
Яссин ЭЛАЛАУИ
источник
13

в Ubuntu с использованием PHP 5.59
:

/etc/php5/cli/conf.d

и найдите ваш xdebug.ini в этом каталоге , в моем случае это 20-xdebug.ini

и добавьте эту строку

xdebug.max_nesting_level = 200


или это

xdebug.max_nesting_level = -1

установите его на -1, и вам не нужно беспокоиться об изменении значения уровня вложенности.

`

Гуджарат Сантана
источник
12

вероятно произошло из-за xdebug.

Попробуйте прокомментировать следующую строку в вашем «php.ini» и перезапустите сервер, чтобы перезагрузить PHP.

  ";xdebug.max_nesting_level"

vandersondf
источник
2
или отключил все
xdebug
2
Как это будет работать? Если вы не определите предел вручную, он просто вернется к значению по умолчанию, равному 100 ( xdebug.org/docs/basic ). Комментируя эту строку, все, что вы делаете, заставляет настройку вернуться к значению по умолчанию.
другой программист
Отключать все xdebug не рекомендуется, если вы зависите от его использования инструментом; Обычно конфигурация "xdebug.max_nesting_level" используется без знания его реального использования, поэтому обычно достаточно только комментария и он действителен.
vandersondf
12

Попробуйте поискать в /etc/php5/conf.d/, чтобы увидеть, есть ли файл с именем xdebug.ini

по умолчанию max_nesting_level равен 100

Если он не установлен в этом файле, добавьте:

xdebug.max_nesting_level=300

до конца списка, так это выглядит так

xdebug.remote_enable=on
xdebug.remote_handler=dbgp
xdebug.remote_host=localhost
xdebug.remote_port=9000
xdebug.profiler_enable=0
xdebug.profiler_enable_trigger=1
xdebug.profiler_output_dir=/home/drupalpro/websites/logs/profiler
xdebug.max_nesting_level=300

Затем вы можете использовать тест @ Andrey до и после внесения этого изменения, чтобы проверить, сработало ли оно.

php -r 'function foo() { static $x = 1; echo "foo ", $x++, "\n"; foo(); } foo();'
Ли Вудман
источник
Отлично, первый ответ, в котором упоминается, что xdebug имеет отдельный .iniфайл. Кстати, когда вы запускаете php5-fpm, этот файл, вероятно, где-то здесь:/etc/php5/fpm/conf.d/20-xdebug.ini
Daan
7

php.ini:

xdebug.max_nesting_level = -1

Я не совсем уверен, будет ли значение когда-либо переполнено и достигнет -1, но оно либо никогда не достигнет -1, либо установит max_nesting_level довольно высоким.

Мартын Шотт
источник
Оно работает! Неважно, используете ли вы XDebug или нет, ни комментируете строку в php.ini. Я явно использовал: ini_set ('xdebug.max_nesting_level', -1);
user2928048
6

Вы можете преобразовать свой рекурсивный код в итеративный код, который имитирует рекурсию. Это означает, что вы должны помещать текущее состояние (URL, документ, положение в документе и т. Д.) В массив при достижении ссылки и извлекать ее из массива после завершения этой ссылки.

Йог
источник
5

Вы можете попытаться развернуть вложенность путем реализации параллельных рабочих (например, в кластерных вычислениях) вместо увеличения количества вызовов вложенных функций.

Например: вы определяете ограниченное количество слотов (например, 100) и отслеживаете количество «рабочих», назначенных каждому / некоторым из них. Если какие-либо слоты становятся свободными, вы помещаете ожидающих работников «в них».

tamasgal
источник
1
Это не совсем применимый подход. Разумнее распараллеливать, а не избегать глубины стека.
aredridel
5

Проверьте рекурсию из командной строки:

php -r 'function foo() { static $x = 1; echo "foo ", $x++, "\n"; foo(); } foo();'

если результат> 100 ТО, проверьте лимит памяти;

Андрей
источник
3

Если вы используете Laravel, сделайте

composer update

Это должно быть работой.

Путри Деви Пурнамасари
источник
Вы должны добавить дополнительную справочную информацию об этом. Это может быть полезным , хотя laracasts.com/forum/...
ggderas
1
это не имеет отношения к настройкам xdebug / php.ini, которые могут быть причиной ошибки. Также возможно, что ваше приложение находится в цикле DOS и непрерывно зацикливается на функции, где OP указывал, что они использовали laravel и, глядя на его код, скорее всего, он будет codeigniter
Джеймс Киркби,
3
<?php
ini_set('xdebug.max_nesting_level', 9999);
... your code ...

PS Измените 9999 на любой номер, который вы хотите.

cofirazak
источник
1

У меня была ошибка, когда я устанавливал много плагинов. Итак, ошибка 100 показала, включая местоположение последнего плагина, который я установил C: \ wamp \ www \ mysite \ wp-content \ plugins \ "...", поэтому я удалил этот плагин папка на диске C: тогда все вернулось к нормальному состоянию. Я думаю, что мне нужно ограничить количество подключаемых модулей, которые я установил или активировал. Удачи, я надеюсь, это поможет

CalvinMD
источник
1

В вашем случае это определенно, что у экземпляра сканера больше предела Xdebug для отслеживания ошибок и отладочной информации.

Но в других случаях такие ошибки, как в PHP или основных файлах, таких как библиотеки CodeIgniter, создадут такой случай, и если вы даже увеличите настройку уровня x-debug, она не исчезнет.

Итак, внимательно изучите ваш код :).

Здесь была проблема в моем случае.

У меня был класс обслуживания, который является библиотекой в ​​CodeIgniter. Имея функцию внутри, как это.

 class PaymentService {

    private $CI;

    public function __construct() {

        $this->CI =& get_instance();

   }

  public function process(){
   //lots of Ci referencing here...
   }

Мой контроллер следующим образом:

$this->load->library('PaymentService');
$this->process_(); // see I got this wrong instead  it shoud be like 

Вызов функции в последней строке был неправильным из-за опечатки, вместо этого он должен был выглядеть так:

$this->Payment_service->process(); //the library class name

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

Даниэль Аденью
источник
Это ответ или вопрос?
AL
@daniedad Я отредактировал ваш ответ, я думаю, что лучше написать решение в тексте, а не только в комментариях, прикрепленных к коду. И нынешняя форма заставила меня думать, что это новый вопрос, а не ответ. Не стесняйтесь отменить, если вы не одобряете изменения.
AL
1

У меня была эта проблема с WordPress на cloud9. Оказывается, это был плагин W3 Caching. Я отключил плагин, и он работал нормально.

пусть будет так
источник
1

Другое решение, если вы запускаете php скрипт в CLI (cmd)

Файл php.ini, который нужно редактировать, отличается в этом случае. В моей установке WAMP файл php.ini, который загружается в командной строке:

\wamp\bin\php\php5.5.12\php.ini

вместо \ wamp \ bin \ apache \ apache2.4.9 \ bin \ php.ini, который загружается при запуске php из браузера

Бинод Калатил
источник
0

Вы также можете изменить функцию {debug} в modifier.debug_print_var.php, чтобы ограничить ее рекурсию в объекты.

Вокруг линии 45, до:

$results .= '<br>' . str_repeat('&nbsp;', $depth * 2)
  . '<b> -&gt;' . strtr($curr_key, $_replace) . '</b> = '
  . smarty_modifier_debug_print_var($curr_val, ++$depth, $length);

После :

$max_depth = 10;
$results .= '<br>' . str_repeat('&nbsp;', $depth * 2)
  . '<b> -&gt;' . strtr($curr_key, $_replace) . '</b> = '
  . ($depth > $max_depth ? 'Max recursion depth:'.(++$depth) : smarty_modifier_debug_print_var($curr_val, ++$depth, $length));

Таким образом, Xdebug будет по-прежнему вести себя нормально: ограничить глубину рекурсии в var_dump и так далее. Так как это умная проблема, а не проблема Xdebug!

theredled
источник
0

У меня была такая же проблема, и я решаю вот так:

Откройте файл MySQL my.ini

В разделе [mysqld] добавьте следующую строку: innodb_force_recovery = 1

Сохраните файл и попробуйте запустить MySQL

Удалите ту строку, которую вы только что добавили, и сохраните

Яссин Эч-Харафи
источник