Solução para “Erro fatal: nível máximo de aninhamento de funções de '100' atingido, abortando!” em PHP

137

Eu criei uma função que localiza todos os URLs em um arquivo html e repete o mesmo processo para cada conteúdo html vinculado aos URLs descobertos. A função é recursiva e pode continuar indefinidamente. No entanto, limitei a recursão ao definir uma variável global que faz com que a recursão pare após 100 recursões.

No entanto, php retorna este erro:

Erro fatal: nível máximo de aninhamento de função de '100' atingido, abortando! em D: \ wamp \ www \ crawler1 \ simplehtmldom_1_5 \ simple_html_dom.php na linha 1355

ERRO

Encontrei uma solução aqui: Aumentar o limite de chamadas da função de aninhamento, mas isso não está funcionando no meu caso.

Estou citando uma das respostas do link mencionado acima. Por favor, considere isso.

"Você possui o Zend, o IonCube ou o xDebug instalado? Nesse caso, provavelmente é de onde você está recebendo esse erro.

Eu me deparei com isso há alguns anos atrás, e acabou sendo o Zend colocando esse limite lá, não o PHP. É claro que removê-lo permitirá que você ultrapasse as 100 iterações, mas acabará atingindo os limites de memória. "

Existe uma maneira de aumentar o nível máximo de aninhamento de funções no PHP

Rafay
fonte
2
Além disso: o PHP não tem um limite para chamadas de funções aninhadas, deve ser uma extensão que você está usando que causa isso.
Abel
@ Abel Tenho certeza de que meu código não possui erros. Há uma variável estática que incrementa seu valor em um em cada chamada recursiva. Se essa variável for menor que 100, as chamadas recursivas continuarão até que a variável atinja 100. Quero dizer que a variável que atinge 100 é realmente o caso base. Enquanto o erro surge antes de 100 recursões. E como você mencionou que alguma extensão pode estar causando isso, eu gostaria de mencionar que estou usando funções do simple_html_dom.php. Se você tem alguma idéia sobre o simple_html_dom.php, ajude-me a esse respeito. Consulte a pergunta atualizada.
Rafay
7
Isso é um erro do xdebug. Na captura de tela, é visível que você usa o xdebug. Você pode desativar a configuração aqui: xdebug.max_nesting_level ou informar o tamanho do nível de aninhamento.
hakre
3
se usar o WAMP, observe que desabilitar o xdebug no php.ini nem sempre funciona; o mesmo se aplica à extensão do nível de aninhamento permitido; um bug um palpite; SOLUÇÃO: ir para php.ini e comentário fora php_xdebug - ??? DLL.
Jeffz

Respostas:

145

Aumente o valor do xdebug.max_nesting_levelseuphp.ini

Maxence
fonte
6
@AL Você edita seu arquivo php.ini e adiciona ou edita a linha xdebug.max_nesting_level na seção XDebug.
Maxence
3
No entanto, se este for um ambiente de produção, consulte a resposta aceita, que é desativar o xdebug nesse ambiente.
Zkent 06/07/2015
3
Isso resolve o sintoma (por um tempo), mas não o problema.
Sebastian Mach
1
Essa solução funcionou para mim quando eu estava usando o UFront for Haxe no MAMP.
Confidente
4
para ilimitado:xdebug.max_nesting_level = -1
Nabi KAZ
55

Uma solução simples resolveu meu problema. Eu apenas comentei esta linha:

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

no meu php.iniarquivo Esta extensão estava limitando a pilha para 100que eu a desabilitei. A função recursiva agora está funcionando como previsto.

Rafay
fonte
4
Então, afinal, era a extensão XDebug, afinal ... É bom saber. Em dois dias, você pode aceitar sua própria resposta como resposta aceita, se desejar (e dar uma olhada nas perguntas anteriores, a maioria perde uma resposta aceita).
Abel
61
Lidar com a recursão excessiva é certamente melhor do que simplesmente desligar o monitoramento.
precisa saber é
7
Essa é uma abordagem pesada. As respostas acima que mencionam a variável para ajustar a profundidade máxima da pilha são uma abordagem melhor.
Aredridel 4/12
7
Você deve não ter o xdebug ativado em um ambiente de produção.
HarryFink 02/12/13
2
puta merda. Não consigo parar de rir da solução escolhida. Para que meu PC não parasse de fazer barulho, encontrei a solução. Desligue isso. :)
Kevin Remisoski
44

Em vez de fazer chamadas de função recursivas, trabalhe com um modelo de fila para nivelar a estrutura.

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

Existem diferentes maneiras de lidar com isso. Você pode acompanhar mais informações se precisar de algumas dicas sobre a origem ou os caminhos percorridos. Também existem filas distribuídas que podem funcionar com um modelo semelhante.

Louis-Philippe Huberdeau
fonte
5
Com o SPL, você não precisa reinventar a fila: php.net/manual/en/class.splqueue.php #
Francesco
1
A fila SPL pode fornecer um pouco mais de velocidade, mas eu gosto de manter matrizes para as tarefas mais simples. push / pop / shift / unshift são fornecidos.
Louis-Philippe Huberdeau
1
Essa é a resposta correta. Evite alterar os valores padrão. Tente otimizar seu código.
Junaid Atique
41

Outra solução é adicionar xdebug.max_nesting_level = 200no seu php.ini

bacar ndiaye
fonte
8
também é possível fazê-lo em php, por exemplo, no arquivo de configuração do seu projeto. ini_set('xdebug.max_nesting_level', 200);
svassr
@htxryan Não sou especialista, mas isso se deve ao fato de sua pilha de chamadas ser muito "profunda" (muitas funções chamando outras funções). O cenário típico em que isso ocorre é com uma função recursiva. A configuração provavelmente está lá para evitar a recursão "fora de controle" devido a um erro no código.
187 Bryan #
@svassr você pode querer considerar adicionar essa dica como uma resposta separada ou adicionar a uma já existente, foi útil para mim, mas quase não percebi nos comentários
Bryan
@Bryan acabou de adicionar uma resposta
svassr
23

Em vez de desativar o xdebug, você pode definir o limite mais alto como

xdebug.max_nesting_level = 500

shahinam
fonte
@SebastianMach: e, surpreendentemente, anos depois também. :) (Mais quatro vezes, mais ou menos. As pessoas não apenas não leem agora, nem sequer rolam mais.)
Sz.
1
@Sz .: Uau, que explosão do passado: P Surpreendentemente chocante.
Sebastian Mach
18

Também é possível corrigir isso diretamente no php, por exemplo, no arquivo de configuração do seu projeto.

ini_set('xdebug.max_nesting_level', 200);

svassr
fonte
1
Obrigado, isso funciona muito bem, pois não preciso me preocupar em atualizar o php.ini em todas as minhas caixas de desenvolvimento, apenas adiciono isso ao arquivo de inicialização do meu aplicativo.
19715 Bryan
13

Entre no seu arquivo de configuração php.ini e altere a seguinte linha:

xdebug.max_nesting_level=100

para algo como:

xdebug.max_nesting_level=200
Yasssine ELALAOUI
fonte
13

no Ubuntu usando PHP 5.59:
chegou ao `:

/etc/php5/cli/conf.d

e encontre seu xdebug.ini nesse diretório, no meu caso é 20-xdebug.ini

e adicione esta linha `

xdebug.max_nesting_level = 200


ou isto

xdebug.max_nesting_level = -1

defina-o como -1 e você não precisa se preocupar em alterar o valor do nível de aninhamento.

`

Gujarat Santana
fonte
12

provavelmente aconteceu por causa do xdebug.

Tente comentar a seguinte linha no seu "php.ini" e reinicie o servidor para recarregar o PHP.

  ";xdebug.max_nesting_level"

vandersondf
fonte
2
ou desativados todos xdebug
zloctb
2
Como isso funcionaria? Se você não definir manualmente o limite, ele voltará ao padrão, que é 100 ( xdebug.org/docs/basic ). Ao comentar esta linha, tudo o que você faz força a configuração a voltar ao padrão.
Justanotherprogrammer
Desabilitar todo o xdebug não é recomendado se você depende do uso da ferramenta; Normalmente, a configuração "xdebug.max_nesting_level" é usada sem conhecer seu uso real; portanto, geralmente apenas comentários são suficientes e válidos.
Vandersondf
12

Tente procurar em /etc/php5/conf.d/ para ver se existe um arquivo chamado xdebug.ini

max_nesting_level é 100 por padrão

Se não estiver definido nesse arquivo, adicione:

xdebug.max_nesting_level=300

até o final da lista para que fique assim

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

você pode usar o teste de @ Andrey antes e depois de fazer essa alteração para ver se funcionou.

php -r 'function foo() { static $x = 1; echo "foo ", $x++, "\n"; foo(); } foo();'
Lee Woodman
fonte
Ótimo, a primeira resposta que menciona que o xdebug tem um .iniarquivo separado . A propósito, quando você executa o php5-fpm, esse arquivo provavelmente está em algum lugar aqui:/etc/php5/fpm/conf.d/20-xdebug.ini
Daan
7

php.ini:

xdebug.max_nesting_level = -1

Não tenho certeza se o valor excederá o valor -1, mas nunca atingirá -1 ou definirá o max_nesting_level bastante alto.

Martyn Shutt
fonte
Funciona! Não importa se você usa o XDebug ou não, nem se você comenta a linha no php.ini. Eu usei explicitamente: ini_set ('xdebug.max_nesting_level', -1);
User2928048
6

Você pode converter seu código recursivo em um código iterativo, que simula a recursão. Isso significa que você precisa enviar o status atual (url, documento, posição no documento etc.) para uma matriz, quando você acessa um link, e removê-lo da matriz, quando esse link é concluído.

Yogu
fonte
5

Você pode tentar mover o aninhamento implementando trabalhadores paralelos (como na computação em cluster) em vez de aumentar o número de chamadas de função de aninhamento.

Por exemplo: você define um número limitado de slots (por exemplo, 100) e monitora o número de "trabalhadores" atribuídos a cada um deles. Se algum slot ficar livre, você coloca os trabalhadores em espera "neles".

tamasgal
fonte
1
Essa não é realmente uma abordagem geralmente aplicável. É mais sensato paralelizar, não evitar a profundidade da pilha.
Aredridel #
5

Verifique a recursão na linha de comando:

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

se resultado> 100 ENTÃO verifique o limite de memória;

Andrey
fonte
3

Se você estiver usando o Laravel, faça

composer update

Isso deve ser trabalho.

Putri Dewi Purnamasari
fonte
Você deve adicionar mais informações básicas sobre isso. Isto pode ser útil, embora laracasts.com/forum/...
ggderas
1
isso não afeta as configurações do xdebug / php.ini, que podem ser a causa do erro. Também é possível sua aplicação é em um loop dos e continuamente looping em torno de uma função, não de onde OP estado em que estavam usando laravel e olhando para o seu código de saborear a sua probabilidade de ser codeigniter
James Kirkby
3
<?php
ini_set('xdebug.max_nesting_level', 9999);
... your code ...

PS Altere 9999 para o número que desejar.

cofirazak
fonte
1

Ocorreu um erro ao instalar muitos plugins. Portanto, o erro 100 mostrou a localização do último plug-in em que eu instalei C: \ wamp \ www \ mysite \ wp-content \ plugins \ "..." e excluí esse plug-in pasta na unidade C: então tudo voltou ao normal.Eu acho que tenho que limitar a quantidade de plug-in que instalo ou ativei. boa sorte espero que ajude

CalvinMD
fonte
1

No seu caso, é definitivamente a instância do rastreador que possui mais limites Xdebug para rastrear informações de erro e depuração.

Mas, em outros casos, também erros como no PHP ou arquivos principais como as bibliotecas CodeIgniter criarão esse caso e, se você aumentar a configuração do nível de depuração x, ele não desaparecerá.

Então, examine seu código com cuidado :).

Aqui estava o problema no meu caso.

Eu tinha uma classe de serviço que é uma biblioteca no CodeIgniter. Tendo uma função dentro como esta.

 class PaymentService {

    private $CI;

    public function __construct() {

        $this->CI =& get_instance();

   }

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

Meu controlador da seguinte forma:

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

A chamada de função na última linha estava incorreta por causa do erro de digitação. Em vez disso, deveria ter sido como abaixo:

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

Então eu estava recebendo a mensagem de erro exceder. Mas eu desativei o XDebug, mas não ajudei. De qualquer forma, verifique o nome da sua classe ou seu código para obter uma chamada de função adequada.

Daniel Adenew
fonte
É uma resposta ou uma pergunta?
AL
@daniedad Editei sua resposta, acho que é melhor escrever a solução em texto e não apenas nos comentários anexados ao código. E a forma atual me fez pensar que era uma nova pergunta e não uma resposta. Sinta-se à vontade para reverter se você reprovar as alterações.
AL
1

Eu tive esse problema com o WordPress na cloud9. Acontece que foi o plugin W3 Caching. Desativei o plugin e funcionou bem.

que assim seja
fonte
1

Outra solução se você estiver executando o script php na CLI (cmd)

O arquivo php.ini que precisa ser editado é diferente nesse caso. Na minha instalação do WAMP, o arquivo php.ini carregado na linha de comando é:

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

em vez de \ wamp \ bin \ apache \ apache2.4.9 \ bin \ php.ini, que é carregado quando o php é executado no navegador

Binod Kalathil
fonte
0

Você também pode modificar a função {debug} em modifier.debug_print_var.php, para limitar sua recursão em objetos.

Por volta da linha 45, antes:

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

Depois de :

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

Dessa forma, o Xdebug ainda se comportará normalmente: limite a profundidade da recursão em var_dump e assim por diante. Como este é um problema inteligente, não um problema do Xdebug!

theredled
fonte
0

Eu tive o mesmo problema e reslove assim:

Abra o arquivo my.ini do MySQL

Na seção [mysqld], adicione a seguinte linha: innodb_force_recovery = 1

Salve o arquivo e tente iniciar o MySQL

Remova a linha que você acabou de adicionar e salve

Yassine Ech-Charafi
fonte