Rozwiązanie problemu „Błąd krytyczny: osiągnięto maksymalny poziom zagnieżdżenia funkcji„ 100 ”, przerywanie!” w PHP


137

Zrobiłem funkcję, która wyszukuje wszystkie adresy URL w pliku html i powtarza ten sam proces dla każdej treści html połączonej z wykrytymi adresami URL. Funkcja jest rekurencyjna i może trwać bez końca. Jednak ograniczyłem rekursję, ustawiając zmienną globalną, która powoduje zatrzymanie rekursji po 100 rekurencjach.

Jednak php zwraca ten błąd:

Błąd krytyczny: osiągnięto maksymalny poziom zagnieżdżenia funkcji „100”, przerywanie! in D: \ wamp \ www \ crawler1 \ simplehtmldom_1_5 \ simple_html_dom.php on line 1355

BŁĄD

Znalazłem tutaj rozwiązanie: Zwiększenie limitu wywołań funkcji zagnieżdżania, ale to nie działa w moim przypadku.

Cytuję jedną z odpowiedzi z powyższego linku. Proszę, rozważ to.

„Czy masz zainstalowany Zend, IonCube lub xDebug? Jeśli tak, prawdopodobnie jest to źródło tego błędu.

Wpadłem na to kilka lat temu i skończyło się na tym, że Zend stawia to ograniczenie, a nie PHP. Oczywiście usunięcie go pozwoli> przekroczyć 100 iteracji, ale w końcu przekroczysz limity pamięci ”.

Czy istnieje sposób na zwiększenie maksymalnego poziomu zagnieżdżenia funkcji w PHP


2
Ponadto: PHP nie ma limitu wywołań funkcji zagnieżdżonych, musi to być rozszerzenie, którego używasz, które to powoduje.
Abel

@Abel Jestem pewien, że mój kod nie zawiera błędów. Istnieje zmienna statyczna, która zwiększa swoją wartość o jeden przy każdym wywołaniu rekurencyjnym. Jeśli ta zmienna jest mniejsza niż 100, rekurencyjne wywołania trwają, dopóki zmienna nie osiągnie 100. Chodzi mi o to, że zmienna osiągająca 100 jest w rzeczywistości podstawą. Podczas gdy błąd pojawia się przed 100 rekurencjami. Jak wspomniałeś, że niektóre rozszerzenia mogą to powodować, chciałbym wspomnieć, że używam funkcji z pliku simple_html_dom.php. Jeśli masz jakieś pojęcie o simple_html_dom.php, pomóż mi w tym zakresie. Proszę odnieść się do zaktualizowanego pytania.
Rafay

7
To jest błąd xdebug. Ze zrzutu widać, że używasz xdebug. Możesz wyłączyć to ustawienie tutaj: xdebug.max_nesting_level lub określić, jak duży jest poziom zagnieżdżenia.
hakre

3
jeśli używasz WAMP, pamiętaj, że wyłączenie xdebug w php.ini NIE zawsze działa; to samo dotyczy rozszerzania poziomu dozwolonego zagnieżdżenia; błąd zgadywanie; ROZWIĄZANIE: przejdź do php.ini i skomentuj php_xdebug - ???.
Dll

Odpowiedzi:


145

Zwiększ wartość xdebug.max_nesting_levelw swoimphp.ini


6
@AL Edytujesz swój plik php.ini i dodajesz lub edytujesz wiersz xdebug.max_nesting_level w sekcji XDebug.
Maxence,

3
Jeśli jednak jest to środowisko produkcyjne, zobacz akceptowaną odpowiedź, która polega na wyłączeniu xdebug w tym środowisku.
zkent

3
To rozwiązuje symptom (na chwilę), ale nie rozwiązuje problemu.
Sebastian Mach

1
To rozwiązanie zadziałało, gdy używałem UFront dla Haxe na MAMP.
Confidant

4
bez ograniczeń:xdebug.max_nesting_level = -1
Nabi KAZ

55

Proste rozwiązanie rozwiązało mój problem. Właśnie skomentowałem tę linię:

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

w moim php.inipliku. To rozszerzenie ograniczało stos do, 100więc je wyłączyłem. Funkcja rekurencyjna działa teraz zgodnie z oczekiwaniami.


4
Więc ostatecznie było to rozszerzenie XDebug ... Dobrze wiedzieć. W ciągu dwóch dni możesz zaakceptować własną odpowiedź jako zaakceptowaną, jeśli chcesz (i spójrz na swoje poprzednie pytania, większość z nich pomija zaakceptowaną odpowiedź).
Abel

61
Radzenie sobie z nadmierną rekurencją jest z pewnością lepsze niż zwykłe wyłączenie monitorowania.
petesiss

7
To twarde podejście. Powyższe odpowiedzi, które wspominają o zmiennej dostosowującej maksymalną głębokość stosu, są lepszym podejściem.
aredridel

7
Nie powinieneś mieć włączonego xdebug w środowisku produkcyjnym.
HarryFink

2
o kurczę. Nie mogę przestać się śmiać z wybranego rozwiązania. Więc mój komputer nie przestawał hałasować, więc znalazłem rozwiązanie. Wyłącz to. :)
Kevin Remisoski

44

Zamiast korzystać z rekurencyjnych wywołań funkcji, pracuj z modelem kolejki, aby spłaszczyć strukturę.

$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;
}

Istnieją różne sposoby radzenia sobie z tym. Możesz śledzić więcej informacji, jeśli potrzebujesz wglądu w początek lub pokonywane ścieżki. Istnieją również kolejki rozproszone, które mogą działać na podobnym modelu.


5
Dzięki SPL nie musisz wymyślać kolejki na nowo: php.net/manual/en/class.splqueue.php
Francesco

1
Kolejka SPL może zapewniać nieco większą prędkość, ale lubię trzymać się tablic w przypadku większości prostych zadań. push / pop / shift / unshift są dostępne.
Louis-Philippe Huberdeau

1
To jest poprawna odpowiedź. Unikaj zmiany wartości domyślnych. Spróbuj zoptymalizować swój kod.
Junaid Atique

41

Innym rozwiązaniem jest dodanie xdebug.max_nesting_level = 200pliku php.ini


8
można to również zrobić w php, na przykład w pliku konfiguracyjnym projektu. ini_set('xdebug.max_nesting_level', 200);
svassr

@htxryan Nie jestem ekspertem, ale jest to spowodowane zbyt głębokim stosem wywołań (zbyt wiele funkcji wywołujących inne funkcje). Typowy scenariusz, w którym to się dzieje, to funkcja rekurencyjna. To ustawienie najprawdopodobniej pozwala uniknąć rekurencji „poza kontrolą” z powodu błędu w kodzie.
Bryan,

@svassr możesz rozważyć dodanie tej wskazówki jako oddzielnej odpowiedzi lub dodanie do istniejącej, było to dla mnie pomocne, ale prawie przegapiłem to w komentarzach
Bryan

@Bryan właśnie dodał odpowiedź
svassr

23

Zamiast wyłączać xdebug, możesz ustawić wyższy limit, na przykład

xdebug.max_nesting_level = 500


@SebastianMach: i, co zaskakujące, również po latach. :) (Jeszcze cztery razy. Ludzie nie dość, że teraz nie czytają, już nawet nie przewijają.)
Sz.

1
@Sz .: Wow, co za podmuch z przeszłości: P Niezwykle szokujące.
Sebastian Mach,

18

Można to również naprawić bezpośrednio w php, na przykład w pliku konfiguracyjnym projektu.

ini_set('xdebug.max_nesting_level', 200);


1
Dzięki, to działa ładnie, ponieważ nie muszę się martwić o aktualizację php.ini na wszystkich moich programach, po prostu dodaję to do pliku bootstrap mojej aplikacji.
Bryan

13

Wejdź do pliku konfiguracyjnego php.ini i zmień następujący wiersz:

xdebug.max_nesting_level=100

na coś takiego:

xdebug.max_nesting_level=200

13

na Ubuntu przy użyciu PHP 5.59:
trzeba:

/etc/php5/cli/conf.d

i znajdź swój xdebug.ini w tym katalogu , w moim przypadku jest to 20-xdebug.ini

i dodaj tę linię `

xdebug.max_nesting_level = 200


albo to

xdebug.max_nesting_level = -1

ustaw ją na -1 i nie musisz się martwić o zmianę wartości poziomu zagnieżdżenia.

`


12

prawdopodobnie stało się to z powodu xdebug.

Spróbuj skomentować następujący wiersz w swoim „php.ini” i zrestartuj serwer, aby przeładować PHP.

  ";xdebug.max_nesting_level"


2
lub wyłączone wszystkie xdebug
zloctb

2
Jak by to działało? Jeśli nie zdefiniujesz ręcznie limitu, po prostu powrócisz do wartości domyślnej, czyli 100 ( xdebug.org/docs/basic ). Komentując tę ​​linię, wszystko, co robisz, wymusza przywrócenie ustawienia domyślnego.
justanotherprogrammer

Wyłączanie wszystkich xdebug nie jest zalecane, jeśli polegasz na jego używaniu; Zwykle konfiguracja "xdebug.max_nesting_level" jest używana bez znajomości jego rzeczywistego zastosowania, więc generalnie tylko komentarz jest wystarczający i ważny.
vandersondf

12

Spróbuj poszukać w /etc/php5/conf.d/, aby sprawdzić, czy jest plik o nazwie xdebug.ini

max_nesting_level to domyślnie 100

Jeśli nie jest ustawiony w tym pliku, dodaj:

xdebug.max_nesting_level=300

do końca listy, więc wygląda to tak

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

możesz następnie użyć testu @ Andrey'a przed i po wprowadzeniu tej zmiany, aby sprawdzić, czy zadziałało.

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

Świetnie, pierwsza odpowiedź, która wspomina, że ​​xdebug ma osobny .iniplik. Nawiasem mówiąc, kiedy uruchamiasz php5-fpm ten plik prawdopodobnie jest gdzieś tutaj:/etc/php5/fpm/conf.d/20-xdebug.ini
Daan

7

php.ini:

xdebug.max_nesting_level = -1

Nie jestem do końca pewien, czy wartość kiedykolwiek się przepełni i osiągnie -1, ale albo nigdy nie osiągnie -1, albo ustawia max_nesting_level dość wysoko.


To działa! Nieważne, czy używasz XDebug, czy nie, ani jeśli zakomentujesz linię w php.ini. Jawnie użyłem: ini_set ('xdebug.max_nesting_level', -1);
user2928048

6

Możesz przekonwertować swój rekurencyjny kod na kod iteracyjny, który symuluje rekurencję. Oznacza to, że musisz wypchnąć aktualny stan (adres URL, dokument, pozycja w dokumencie itp.) Do tablicy, gdy dotrzesz do łącza, i wyskoczyć z tablicy, gdy ten link się skończy.


5

Możesz spróbować ograniczyć zagnieżdżanie, wdrażając równoległe procesy robocze (jak w przypadku obliczeń klastrowych) zamiast zwiększać liczbę wywołań funkcji zagnieżdżania.

Na przykład: definiujesz ograniczoną liczbę slotów (np. 100) i monitorujesz liczbę „pracowników” przypisanych do każdego / niektórych z nich. Jeśli któryś z miejsc stanie się wolny, umieszczasz w nim oczekujących pracowników.


1
To nie jest ogólnie stosowane podejście. Bardziej rozsądne jest zrównoleglenie, a nie unikanie głębokości stosu.
aredridel

5

Sprawdź rekursję z wiersza poleceń:

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

jeśli wynik> 100 TO sprawdź limit pamięci;


3

Jeśli używasz Laravel, zrób

composer update

To powinno działać.


Powinieneś dodać więcej podstawowych informacji na ten temat. Może to być przydatne, chociaż laracasts.com/forum/ ...
ggderas

1
nie ma to wpływu na ustawienia xdebug / php.ini, które mogą być przyczyną błędu. Możliwe jest również, że aplikacja jest w pętli DOS i ciągle zapętla się wokół funkcji, nie ma miejsca, w którym OP stwierdził, że używali laravela i patrząc na jego kod sip, prawdopodobnie jest to Codeigniter
James Kirkby

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

PS Zmień 9999 na dowolną liczbę.


1

Wystąpił błąd podczas instalowania wielu wtyczek, więc pokazał się błąd 100 zawierający lokalizację ostatniej zainstalowanej wtyczki C: \ wamp \ www \ mysite \ wp-content \ plugins \ "..." więc usunąłem tę wtyczkę folder na dysku C: wszystko wróciło do normy Myślę, że muszę ograniczyć ilość zainstalowanej wtyczki lub aktywowałem. powodzenia mam nadzieję, że to pomoże


1

W twoim przypadku zdecydowanie instancja robota ma większy limit Xdebug do śledzenia błędów i informacji debugowania.

Ale w innych przypadkach również błędy, takie jak w PHP lub plikach core, takich jak biblioteki CodeIgniter, utworzą taki przypadek i jeśli nawet zwiększysz ustawienie poziomu x-debug, nie zniknie.

Przyjrzyj się więc uważnie swojemu kodowi :).

Tutaj był problem w moim przypadku.

Miałem klasę usług, która jest biblioteką w CodeIgniter. Mając wewnątrz taką funkcję.

 class PaymentService {

    private $CI;

    public function __construct() {

        $this->CI =& get_instance();

   }

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

Mój kontroler w następujący sposób:

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

Wywołanie funkcji w ostatniej linii było błędne z powodu literówki, zamiast tego powinno wyglądać jak poniżej:

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

Następnie otrzymywałem komunikat o błędzie przekroczenia. Ale wyłączyłem XDebug, ale nie pomogło. W każdym razie sprawdź nazwę klasy lub kod pod kątem prawidłowego wywołania funkcji.


Czy to odpowiedź czy pytanie?
AL

@daniedad edytowany swoją odpowiedź, myślę, że lepiej napisać rozwiązanie w tekście, a nie tylko w komentarzach dołączonych do kodu. A obecna forma sprawiła, że ​​pomyślałem, że to nowe pytanie, a nie odpowiedź. Jeśli odrzucisz zmiany, możesz je wycofać.
AL

1

Miałem ten problem z WordPress na cloud9. Okazuje się, że była to wtyczka W3 Caching. Wyłączyłem wtyczkę i działało dobrze.


1

Inne rozwiązanie, jeśli uruchamiasz skrypt php w CLI (cmd)

Plik php.ini, który wymaga edycji, jest w tym przypadku inny. W mojej instalacji WAMP plik php.ini, który jest ładowany w wierszu poleceń, to:

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

zamiast \ wamp \ bin \ apache \ apache2.4.9 \ bin \ php.ini, który ładuje się, gdy php jest uruchamiany z przeglądarki


0

Możesz także zmodyfikować funkcję {debug} w modifier.debug_print_var.php, aby ograniczyć rekursję do obiektów.

Wokół linii 45, przed:

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

Po :

$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));

W ten sposób Xdebug nadal będzie zachowywał się normalnie: ogranicz głębokość rekursji w var_dump i tak dalej. Ponieważ jest to drobny problem, a nie Xdebug!


0

Miałem ten sam problem i tak mi się podoba:

Otwórz plik MySQL my.ini

W sekcji [mysqld] dodaj następujący wiersz: innodb_force_recovery = 1

Zapisz plik i spróbuj uruchomić MySQL

Usuń tę linię, którą właśnie dodałeś i Zapisz

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.