Archive for the ‘Modulecategory

Erro PHP aninhando o nível de dependência recursiva muito profundo

12 de março, 2010

Eu instalei o PHP 5.2 em um dos meus computadores testes hoje e um par de pedaços de código que anteriormente trabalhou muito bem na versão 5.1.6 jogou a erros fatais na nova versão. A mensagem de erro era de "nível de aninhamento demasiado profundo – dependência recursiva?"e levou um pouco de tempo

para localizar a raiz do problema. Aqui está o que eu tinha feito errado.

No PHP existem dois operadores de comparação, = = e = = =. É geralmente conhecido que o primeiro não é rigoroso sobre o tipo, mas o segundo é. Então, por exemplo

Eco ( false = = 0 ); // verdadeiro

Eco ( false = = = 0 ); // falso

– 0 é um número inteiro e false é um boolean

Meu problema surgiu a partir de uso de digitação não-estrita com objetos.

$um = MyObj novo();
$b = MyObj novo();
se( $um = = $b )

Eu não tinha pensado que eu estava fazendo com esse código. Ao comparar dois objetos usando o operador de comparação não-estrita (==) PHP compara todas as propriedades dos objetos e se combinam com os objetos são considerados iguais. Se eles não corresponderem, eles não são iguais. Em vigor, Temos uma comparação recursiva de todas as propriedades de cada objeto, e todas as suas propriedades, etc. até chegarmos a tipos de dados básicos, como sequências de caracteres e números inteiros.

Se, no entanto, Utilizamos a comparação estrita (===), PHP irá verificar se os dois objetos são exatamente o mesmo objeto., Não apenas objetos com as mesmas propriedades.

classe MyObj
{
público $p;
}

$um = MyObj novo();
$b = MyObj novo();
$c = MyObj novo();
$um->p = 1;
$b->p = 1;
$c->p = 2;
Eco ( $um = = $c ); // falso
Eco ( $um = = $b ); // verdadeiro
Eco ( $um = = = $b ); // falso

O problema surge se você tem referências circulares em suas propriedades de objetos. Então, por exemplo

classe MyObj
{
público $p;
}
classe OtherObj
{
público $q;
}

$um = MyObj novo();
$b = OtherObj novo();
$um->p = $b;
$b->q = $a; // a referência circular: $um->p->q = = = $a

$c = MyObj novo();
$d = OtherObj novo();
$c->p = $d;
$d->q = $c;// outra referência circular: $c->p->q = = = $c

Eco ( $um = = $c ); // Erro fatal:
Aninhamento de nível muito profundo – dependência recursiva?

A fim de comparar a $a para $c, PHP deve comparar suas propriedades. Então a lógica em PHP é algo assim: $um = = $c, se $a ->p = = $c ->p se $a ->p->q = = $c ->p->q se $a ->p->q->p = = $c ->p->q->p etc.. por tempo indeterminado.

PHP 5.1 Parecia a alisar sobre o problema de alguma forma (Provavelmente depois de um certo nível de recursão é simplesmente retornado false) – e geralmente funcionou bem. PHP 5.2 corretamente, produz o erro fatal acima.

Uma vez conhecendo o problema, a solução é fácil – Use a comparação estrita.

Eco ( $um = = = $c ); // falso (e nenhum erro)

A comparação estrita simplesmente irá verificar se os dois objetos estão no mesmo local na memória e assim mesmo se não olhar os valores das propriedades.

OBS.. O mesmo problema pode surgir quando usando os operadores de comparação negado (Use != = em vez de !=) e quando utilizar o in_array (usar o terceiro parâmetro do in_array para indicar comparação rigorosa).