Solution pour "Erreur fatale: niveau maximal d'imbrication des fonctions de '100' atteint, abandon!" en PHP


138

J'ai créé une fonction qui trouve toutes les URL dans un fichier html et répète le même processus pour chaque contenu html lié aux URL découvertes. La fonction est récursive et peut durer indéfiniment. Cependant, j'ai mis une limite à la récursivité en définissant une variable globale qui provoque l'arrêt de la récursivité après 100 récursions.

Cependant, php renvoie cette erreur:

Erreur fatale: niveau maximal d'imbrication des fonctions de «100» atteint, abandon! dans D: \ wamp \ www \ crawler1 \ simplehtmldom_1_5 \ simple_html_dom.php à la ligne 1355

ERREUR

J'ai trouvé une solution ici: augmenter la limite d'appels de fonction d'imbrication mais cela ne fonctionne pas dans mon cas.

Je cite l'une des réponses du lien mentionné ci-dessus. Veuillez y réfléchir.

"Avez-vous installé Zend, IonCube ou xDebug? Si oui, c'est probablement de là que vous obtenez cette erreur.

Je suis tombé dessus il y a quelques années, et c'est finalement Zend qui a mis cette limite là-bas, pas PHP. Bien sûr, le supprimer vous permettra> de dépasser les 100 itérations, mais vous finirez par atteindre les limites de la mémoire. "

Existe-t-il un moyen d'augmenter le niveau d'imbrication maximal des fonctions en PHP


2
Aussi: PHP n'a pas de limite sur les appels de fonctions imbriquées, ce doit être une extension que vous utilisez qui provoque cela.
Abel

@Abel Je suis sûr que mon code ne contient aucune erreur. Il existe une variable statique qui incrémente sa valeur de un à chaque appel récursif. Si cette variable est inférieure à 100, les appels récursifs se poursuivent jusqu'à ce que la variable atteigne 100. Je veux dire que la variable atteignant 100 est en fait le cas de base. Alors que l'erreur survient avant 100 récursions. Et comme vous avez mentionné qu'une extension peut être à l'origine de cela, je tiens à mentionner que j'utilise des fonctions de simple_html_dom.php. Si vous avez une idée de simple_html_dom.php, aidez-moi à cet égard. Veuillez vous référer à la question mise à jour.
Rafay

7
C'est une erreur de xdebug. Sur la capture d'écran, il est visible que vous utilisez xdebug. Vous pouvez désactiver le paramètre ici: xdebug.max_nesting_level ou indiquer la taille du niveau d'imbrication.
hakre

3
si vous utilisez WAMP, notez que la désactivation de xdebug dans php.ini ne fonctionne PAS toujours; il en va de même pour l'extension du niveau de nidification autorisé; un bug une supposition; SOLUTION: allez sur php.ini et commentez php_xdebug - ???.
Dll

Réponses:


145

Augmentez la valeur de xdebug.max_nesting_levelvotrephp.ini


6
@AL Vous éditez votre fichier php.ini et vous ajoutez ou éditez la ligne xdebug.max_nesting_level dans la section XDebug.
Maxence

3
Cependant, s'il s'agit d'un environnement de production, consultez la réponse acceptée, qui consiste à désactiver xdebug dans cet environnement.
zkent

3
Cela résout le symptôme (pendant un certain temps), mais pas le problème.
Sebastian Mach

1
Cette solution a fonctionné pour moi lorsque j'utilisais UFront for Haxe sur MAMP.
Confidant

4
pour illimité:xdebug.max_nesting_level = -1
Nabi KAZ

55

Une solution simple a résolu mon problème. Je viens de commenter cette ligne:

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

dans mon php.inidossier. Cette extension limitait la pile à 100donc je l'ai désactivée. La fonction récursive fonctionne maintenant comme prévu.


4
Donc, finalement c'était l'extension XDebug après tout ... Bon à savoir. Dans deux jours, vous pouvez accepter votre propre réponse comme réponse acceptée, si vous le souhaitez (et jetez un œil à vos questions précédentes, la plupart manquent une réponse acceptée).
Abel

61
Gérer la récursivité excessive est sûrement mieux que de simplement désactiver la surveillance.
petesiss

7
C'est une approche sévère. Les réponses ci-dessus qui mentionnent la variable pour ajuster la profondeur maximale de la pile sont une meilleure approche.
aredridel

7
Vous ne devez pas activer xdebug dans un environnement de production.
HarryFink

2
merde sacrée. Je n'arrête pas de rire de la solution choisie. Donc mon PC n'arrêtait pas de faire du bruit, alors j'ai trouvé la solution. Éteignez-le. :)
Kevin Remisoski

44

Plutôt que d'opter pour des appels de fonction récursifs, utilisez un modèle de file d'attente pour aplatir la structure.

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

Il existe différentes manières de le gérer. Vous pouvez garder une trace de plus d'informations si vous avez besoin d'informations sur l'origine ou les chemins traversés. Il existe également des files d'attente distribuées qui peuvent fonctionner sur un modèle similaire.


5
Avec SPL, vous n'avez pas besoin de réinventer la file d'attente: php.net/manual/en/class.splqueue.php
Francesco

1
SPL Queue peut fournir un peu plus de vitesse, mais j'aime m'en tenir aux tableaux pour les tâches les plus simples. push / pop / shift / unshift sont tous fournis.
Louis-Philippe Huberdeau

1
C'est la bonne réponse. Évitez de modifier les valeurs par défaut. Essayez d'optimiser votre code.
Junaid Atique

41

Une autre solution consiste à ajouter xdebug.max_nesting_level = 200votre php.ini


8
il est également possible de le faire en php, par exemple dans le fichier de configuration de votre projet. ini_set('xdebug.max_nesting_level', 200);
svassr

@htxryan Je ne suis pas un expert mais c'est parce que votre pile d'appels est trop "profonde" (trop de fonctions appelant d'autres fonctions). Le scénario typique où cela se produit est avec une fonction récursive. Le paramètre est le plus susceptible d'éviter la récursivité "hors de contrôle" due à un bogue dans le code.
Bryan

@svassr, vous voudrez peut-être envisager d'ajouter cette astuce en tant que réponse distincte ou de l'ajouter à une réponse existante, cela m'a été utile mais l'a presque manqué dans les commentaires
Bryan

@Bryan vient d'ajouter une réponse
svassr

23

Plutôt que de désactiver xdebug, vous pouvez définir la limite supérieure comme

xdebug.max_nesting_level = 500


@SebastianMach: et, étonnamment, des années après aussi. :) (Comme quatre fois de plus, environ. Non seulement les gens ne lisent pas maintenant, mais ils ne défilent même plus.)
Sz.

1
@Sz .: Wow, quelle explosion du passé: P Incroyablement choquant.
Sebastian Mach

18

Il est également possible de corriger cela directement en php, par exemple dans le fichier de configuration de votre projet.

ini_set('xdebug.max_nesting_level', 200);


1
Merci, cela fonctionne bien car je n'ai pas à me soucier de la mise à jour de php.ini sur toutes mes boîtes de développement, je l'ajoute simplement au fichier de démarrage de mon application.
Bryan

13

Accédez à votre fichier de configuration php.ini et modifiez la ligne suivante:

xdebug.max_nesting_level=100

à quelque chose comme:

xdebug.max_nesting_level=200

13

sur Ubuntu en utilisant PHP 5.59:
allez à `:

/etc/php5/cli/conf.d

et trouvez votre xdebug.ini dans ce répertoire , dans mon cas, c'est 20-xdebug.ini

et ajoutez cette ligne `

xdebug.max_nesting_level = 200


ou ca

xdebug.max_nesting_level = -1

réglez-le sur -1 et vous n'aurez pas à vous soucier de changer la valeur du niveau d'imbrication.

»


12

probablement arrivé à cause de xdebug.

Essayez de commenter la ligne suivante dans votre "php.ini" et redémarrez votre serveur pour recharger PHP.

  ";xdebug.max_nesting_level"


2
ou désactivé tout xdebug
zloctb

2
Comment cela fonctionnerait-il? Si vous ne définissez pas manuellement la limite, elle reviendra simplement à la valeur par défaut, qui est 100 ( xdebug.org/docs/basic ). En commentant cette ligne, tout ce que vous faites force le paramètre à revenir à la valeur par défaut.
justanotherprogrammer

Désactiver tout xdebug n'est pas recommandé si vous dépendez de son utilisation de l'outil; Normalement, la configuration "xdebug.max_nesting_level" est utilisée sans connaître son utilisation réelle, donc généralement seul un commentaire est suffisant et valide.
vandersondf

12

Essayez de chercher dans /etc/php5/conf.d/ pour voir s'il existe un fichier appelé xdebug.ini

max_nesting_level est égal à 100 par défaut

S'il n'est pas défini dans ce fichier, ajoutez:

xdebug.max_nesting_level=300

à la fin de la liste pour qu'il ressemble à ceci

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

vous pouvez ensuite utiliser le test de @ Andrey avant et après avoir effectué cette modification pour voir si cela fonctionne.

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

Super, la première réponse qui mentionne que xdebug a un .inifichier séparé . Au fait, lorsque vous exécutez php5-fpm, ce fichier est probablement quelque part ici:/etc/php5/fpm/conf.d/20-xdebug.ini
Daan

7

php.ini:

xdebug.max_nesting_level = -1

Je ne suis pas tout à fait sûr que la valeur débordera et atteindra -1, mais elle n'atteindra jamais -1, ou elle fixera le max_nesting_level assez haut.


Ça marche! Peu importe si vous utilisez XDebug ou non, ni si vous commentez la ligne dans php.ini. J'ai utilisé explicitement: ini_set ('xdebug.max_nesting_level', -1);
user2928048

6

Vous pouvez convertir votre code récursif en un code itératif, qui simule la récursivité. Cela signifie que vous devez pousser l'état actuel (url, document, position dans le document, etc.) dans un tableau, lorsque vous atteignez un lien, et le sortir du tableau, lorsque ce lien est terminé.


5

Vous pouvez essayer de réduire l'imbrication en implémentant des nœuds de calcul parallèles (comme dans le calcul en cluster) au lieu d'augmenter le nombre d'appels de fonction d'imbrication.

Par exemple: vous définissez un nombre limité d'emplacements (ex. 100) et surveillez le nombre de "travailleurs" affectés à chacun / certains d'entre eux. Si des emplacements deviennent libres, vous mettez les ouvriers en attente "en eux".


1
Ce n'est pas vraiment une approche généralement applicable. C'est plus judicieux de paralléliser, pas d'éviter la profondeur de pile.
aredridel

5

Vérifiez la récursivité depuis la ligne de commande:

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

si résultat> 100 ALORS vérifier la limite de mémoire;


3

Si vous utilisez Laravel, faites

composer update

Cela devrait être du travail.


Vous devriez ajouter plus d'informations générales à ce sujet. Cela pourrait être utile via laracasts.com/forum
...

1
cela n'a aucune incidence sur les paramètres xdebug / php.ini qui pourraient être la cause de l'erreur. Il est également possible que votre application soit dans une boucle dos et tourne en continu autour d'une fonction, nulle part où OP n'a-t-il déclaré qu'il utilisait laravel et en regardant son code siroter son probablement codeigniter
James Kirkby

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

PS Remplacez 9999 par le numéro de votre choix.


1

J'ai eu une erreur lors de l'installation de nombreux plugins, donc l'erreur 100 a montré, y compris l'emplacement du dernier plugin que j'ai installé C: \ wamp \ www \ mysite \ wp-content \ plugins \ "..." donc j'ai supprimé ce plugin dossier sur le lecteur C: alors tout était revenu à la normale.Je pense que je dois limiter la quantité de plug-in que j'installe ou que j'ai activé. bonne chance j'espère que cela aide


1

Dans votre cas, il est certain que l'instance du robot d'exploration a plus de limite Xdebug pour tracer les informations d'erreur et de débogage.

Mais, dans d'autres cas, des erreurs comme sur PHP ou des fichiers core comme les bibliothèques CodeIgniter créeront un tel cas et si vous augmentez même le paramètre de niveau x-debug, il ne disparaîtra pas.

Alors, regardez attentivement votre code :).

Voici le problème dans mon cas.

J'avais une classe de service qui est une bibliothèque dans CodeIgniter. Avoir une fonction à l'intérieur comme ça.

 class PaymentService {

    private $CI;

    public function __construct() {

        $this->CI =& get_instance();

   }

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

Mon contrôleur comme suit:

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

L'appel de fonction sur la dernière ligne était erroné à cause de la faute de frappe, au lieu de cela, il aurait dû être comme ci-dessous:

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

Ensuite, je continuais à recevoir le message d'erreur de dépassement. Mais j'ai désactivé XDebug mais pas aidé. De toute façon, veuillez vérifier le nom de votre classe ou votre code pour un appel de fonction correct.


Est-ce une réponse ou une question?
AL

@daniedad J'ai édité votre réponse, je pense qu'il vaut mieux écrire la solution en texte et pas seulement dans les commentaires attachés au code. Et la forme actuelle m'a fait penser que c'était une nouvelle question et non une réponse. N'hésitez pas à revenir en arrière si vous désapprouvez les modifications.
AL

1

J'ai eu ce problème avec WordPress sur cloud9. Il s'avère que c'était le plugin W3 Caching. J'ai désactivé le plugin et cela a bien fonctionné.


1

Une autre solution si vous exécutez un script php dans la CLI (cmd)

Le fichier php.ini à modifier est différent dans ce cas. Dans mon installation WAMP, le fichier php.ini qui est chargé en ligne de commande est:

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

au lieu de \ wamp \ bin \ apache \ apache2.4.9 \ bin \ php.ini qui se charge lorsque php est exécuté à partir du navigateur


0

Vous pouvez également modifier la fonction {debug} dans modifier.debug_print_var.php, afin de limiter sa récursivité dans les objets.

Vers la ligne 45, avant:

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

Après :

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

De cette façon, Xdebug se comportera toujours normalement: limiter la profondeur de récursivité dans var_dump et ainsi de suite. Comme il s'agit d'un problème intelligent, pas un problème Xdebug!


0

J'ai eu le même problème et j'adore comme ceci:

Ouvrez le fichier MySQL my.ini

Dans la section [mysqld], ajoutez la ligne suivante: innodb_force_recovery = 1

Enregistrez le fichier et essayez de démarrer MySQL

Supprimez cette ligne que vous venez d'ajouter et enregistrez

En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.