2013-08-29 4 views
6

Ich habe den folgenden Code in der Produktion, die eine Endlosschleife verursachen scheint.Verständnis der Operator Vorrang in PHP

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

Wie werden die Vorrangregeln angewendet, die dieses Verhalten verursachen?

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

Ich sehe diese Notiz in der Dokumentation:

Obwohl = hat eine niedrigere Priorität als die meisten anderen Betreiber, wird PHP noch Ausdrücke erlauben ähnlich der folgenden: if (! $ A = foo()), in In diesem Fall wird der Rückgabewert von foo() in $ a gesetzt.

Das lässt mich denken, dass das = zuerst ausgewertet werden sollte. dann ist die ! dann die & &, die keine Endlosschleife verursachen würde.

+0

Haben Sie zu verwenden bedeutet '==' (Vergleich) statt ' = '(Zuweisung) in Ihrer while-Schleife? – vimist

+1

nein, diese Aussage bedeutet wirklich nur, dass'! 'links von' = 'gültig ist. Das' && 'ist immer noch Teil des zugewiesenen Wertes. – Dave

+2

auch: NO. SCHLECHT. Code nicht so. Es ist scheußlich. – Dave

Antwort

2

Der Code wird wie folgt Auswertung:

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

, weshalb Sie die Endlosschleife zu sehen (sobald $z >= 11, $apns falsch ist, so ist die Bedingung immer true). Der Grund für diesen Vorrang ist, dass die Sonderregeln nur für ! auf links der Zuweisung gelten (mit niedrigerer Priorität als =). Es hat keine Auswirkungen auf den booleschen Operator auf der rechten Seite, der sich wie in jeder anderen Sprache verhält.

Ihr Stil ist schlecht. Versuchen Sie dieses, was viel besser lesbar ist und unterscheidet sich nur in den Endwert von $z (und wenn das wichtig ist, können Sie die break Anweisung optimieren.

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); 
} 
+0

Also Es scheint mir, dass $ apns nie etwas anderes als einen booleschen Wert zugewiesen bekommen würde. Recht? Der Rest des Codes, der mit Apple verbunden ist und die Push-Nachricht sendet, würde niemals funktionieren. – digidigo

+0

'$ apns' würde bekommen, was' getApns' zurückgibt. Dies ist ein allgemeines Muster; es wartet effektiv, bis $ apns truthy ist (d. h. nicht null) und dann mit dem Code fortfährt.Beachten Sie, dass der Vergleich nach der Zuweisung angewendet wird und keine Auswirkungen auf den Wert hat, der sich in $ apns befindet. Aber wenn Sie das klarer machen wollen, indem Sie die Aufgabe von der Bedingung trennen, ist das auch gut. – Dave

+1

Im Gegensatz zu meinem früheren Kommentar (jetzt bearbeitet), PHP '' '' '' '' '' und '* * * * konvertieren * die Werte in' true' oder 'false', so dass der ursprüngliche Code immer eine' true' oder 'false gesetzt hätte 'in' $ apns', was bedeutet, dass es nie funktionieren würde. Der Code, den ich gepostet habe, funktioniert. – Dave

2

Ihr Code ist klar Beispiel dafür, warum es ist gute Gewohnheit zu immer alle Bedingungen in Klammern gesetzt (und das gleiche gilt für Codeblock. Auch oneliners sollte von { und } umgeben sein). Anstatt also fehleranfällig:

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

tun

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

und Sie werden sicher sein.