Compreender a precedência do operador em php

Eu tenho o seguinte código na produção que parece estar causando um loop infinito.

$z=1; while (!$apns = $this->getApns($streamContext) && $z < 11) { myerror_log("unable to conncect to apple. sleep for 2 seconds and try again"); $z++; sleep(2); } 

Como as regras de precedência são aplicadas que causam esse comportamento?

http://php.net/manual/en/language.operators.precedence.php

Eu vejo essa nota nos documentos:

Embora tenha menor precedência que a maioria dos outros operadores, o PHP ainda permitirá expressões semelhantes às seguintes: se (! $ A = foo (), caso em que o valor de retorno de foo () é colocado em $ a.

O que me faz pensar que o = deve ser avaliado primeiro. então o ! então o &&, o que não causaria um loop infinito.

Seu código está avaliando assim:

 while (!($apns = ($this->getApns($streamContext) && ($z < 11)))) 

e é por isso que você vê o loop infinito (assim que $z >= 11 , $apns é falso, então a condição sempre é verdadeira). O motivo dessa precedência é que as regras especiais só se aplicam ! à esquerda da atribuição sendo válida (com menor precedência do que = ). Não tem efeito sobre o operador booleano à direita, que se comporta como seria em qualquer linguagem sã.

Seu estilo é ruim. Experimente isso, que é muito mais legível e só difere no valor final de $z (e, se isso for importante, você pode ajustar a declaração de break .

 for( $z = 1; $z < 11; ++ $z ) { // note extra brackets to make it clear that we intend to do assignment not comparison if( ($apns = $this->getApns($streamContext)) ) { break; } myerror_log("unable to conncect to apple. sleep for 2 seconds and try again"); sleep(2); } 

Seu código é um claro exemplo de por que é um bom hábito colocar sempre todas as condições entre parênteses (e o mesmo se aplica ao bloco de código. Mesmo os oneliners devem estar rodeados por { e } ). Então, em vez de propenso a erros:

 while (!$apns = $this->getApns($streamContext) && $z < 11) 

Faz

 while (!($apns = $this->getApns($streamContext)) && ($z < 11)) 

e você estará seguro.

Intereting Posts