Рішення для "Фатальної помилки: Максимальний рівень вкладення функції" 100 "досягнуто, перервавшись!" в PHP


137

Я створив функцію, яка знаходить всі 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


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
Jeffz

Відповіді:


145

Збільште значення xdebug.max_nesting_levelвашихphp.ini


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я його відключив. Рекурсивна функція зараз працює так, як передбачалося.


4
Отже, врешті-решт це було розширення XDebug… Зрештою, це знати. За два дні ви можете прийняти власну відповідь як прийняту відповідь, якщо хочете (і подивіться на попередні запитання, більшість пропускає прийняту відповідь).
Авель

61
Справа з надмірною рекурсією, безумовно, краще, ніж просто вимкнення моніторингу.
petesiss

7
Це важкий підхід. Наведені вище відповіді, в яких згадується змінна для регулювання максимальної глибини стека, є кращим підходом.
aredridel

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
Francesco

1
Черга SPL може забезпечити трохи більшу швидкість, але мені подобається дотримуватися масивів для більшості простих завдань. натискання / поп / зсув / незміна.
Луї-Філіп Хубердо

1
Це правильна відповідь. Уникайте зміни значень за замовчуванням. Спробуйте оптимізувати свій код.
Джунайд Атіке

41

Ще одне рішення - додати xdebug.max_nesting_level = 200у свій php.ini


8
це також можна зробити в php, наприклад, у конфігураційному файлі вашого проекту. ini_set('xdebug.max_nesting_level', 200);
svassr

@htxryan Я не фахівець, але це пов'язано з тим, що стек викликів занадто "глибокий" (занадто багато функцій, що викликають інші функції). Типовий сценарій, коли це відбувається, має рекурсивну функцію. Цей параметр, швидше за все, існує, щоб уникнути "поза контролю" рекурсії через помилку в коді.
Брайан

@svassr Ви можете розглянути можливість додавання цієї поради як окремої відповіді або доповнення до вже існуючої, мені це було корисно, але майже пропустив її в коментарях
Брайан

@Bryan тільки що додав відповідь
svassr

23

Замість того, щоб вимкнути xdebug, ви можете встановити вищу межу, як

xdebug.max_nesting_level = 500


@SebastianMach: і, що дивно, через роки теж. :) (Як і ще чотири рази, або так. Люди не тільки не читають зараз, вони навіть не прокручують більше.)
Sz.

1
@Sz .: Нічого собі, який вибух з минулого: P Дивовижно шокуюче.
Себастьян Мах

18

Це також можна виправити безпосередньо в php, наприклад, у конфігураційному файлі вашого проекту.

ini_set('xdebug.max_nesting_level', 200);


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 в цьому dir, в моєму випадку це 20-xdebug.ini

і додайте цей рядок `

xdebug.max_nesting_level = 200


або це

xdebug.max_nesting_level = -1

встановіть його на -1, і вам не доведеться турбуватися про зміну значення рівня гніздування.

`


12

ймовірно, сталося через xdebug.

Спробуйте прокоментувати наступний рядок у "php.ini" та перезапустіть сервер, щоб перезавантажити PHP.

  ";xdebug.max_nesting_level"


2
або вимкнено всі xdebug
zloctb

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
Даан

7

php.ini:

xdebug.max_nesting_level = -1

Я не зовсім впевнений, що коли-небудь значення переповниться і досягне -1, але воно ніколи не досягне -1, або він встановить максимальний_випуск_рівень досить високим.


Це працює! Незалежно від того, використовуєте ви XDebug чи ні, ні якщо ви коментуєте рядок у php.ini. Я явно використав: ini_set ('xdebug.max_nesting_level', -1);
користувач2928048

6

Ви можете перетворити свій рекурсивний код в ітераційний код, який імітує рекурсію. Це означає, що вам доведеться натиснути поточний статус (URL, документ, позиція в документі тощо) у масив, коли ви досягнете посилання, і вискочити його з масиву, коли це посилання закінчиться.


5

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

Наприклад: ви визначаєте обмежену кількість слотів (наприклад, 100) і стежите за кількістю «працівників», призначених для кожного / деяких з них. Якщо будь-які слоти стають безкоштовними, ви кладете робітників, що чекають, "в них".


1
Це насправді не загальноприйнятний підхід. Це більш розумно паралелізувати, не уникати глибини стеки.
aredridel

5

Перевірте рекурсію з командного рядка:

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

якщо результат> 100 THEN перевірити обмеження пам’яті;


3

Якщо ви використовуєте Laravel, зробіть це

composer update

Це має бути робота.


Ви повинні додати більше довідкової інформації про це. Це може бути корисним, хоча laracasts.com/forum/…
ggderas

1
це не стосується налаштувань xdebug / php.ini, які можуть бути причиною помилки. Можливо також, що ваша програма перебуває в циклі дос і постійно обмотується навколо функції, не де стан штату ОП вони використовували laravel і дивляться на його код ковток, ймовірно, це кодигнатор
Джеймс Кіркбі

3
<?php
ini_set('xdebug.max_nesting_level', 9999);
... your code ...

PS Змініть 9999 на будь-яке число, яке вам потрібно.


1

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


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!


0

У мене була така ж проблема, і я перекладаюсь так:

Відкрийте файл My.QL my.ini

У розділі [mysqld] додайте такий рядок: innodb_force_recovery = 1

Збережіть файл і спробуйте запустити MySQL

Видаліть щойно доданий рядок та збережіть

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.