2015-09-19 8 views
15

(PHP hat || und OR JS nur || hat..)JS vs PHP: Rangzuweisungsoperator bei Verwendung mit logischen oder

JS. Nach MDN|| hat eine höhere Priorität als =. So funktioniert das nicht:

a || a = 1; 

, weil es als ausgewertet hat:

(a || a) = 1; 

, die "in Zuordnung ungültig linke Seite" in einer Folge hat. Ich verstehe das. Das macht Sinn.

PHP. Nach PHP.net funktioniert es das gleiche für PHP: || vor =. Allerdings benutze ich dies die ganze Zeit:

Warum funktioniert es in PHP? Und um das Ganze abzurunden: PHP OR hat niedrigere Priorität als =, so sollten diese nicht das gleiche tun:

$a || $a = 1; 
$a OR $a = 1; 

aber sie tun ... https://3v4l.org/UWXMd

denke ich JS‘|| arbeitet nach MDN des Tisch und OR funktioniert wie PHP Tisch PHP, aber PHP || nicht funktionieren sollte, wie es der Fall ist.

Ist das noch eine weitere seltsame PHP Marotte?

Das Handbuch erwähnt auch dies:

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

Die Präzedenztabelle diktiert PHP (!$a) = foo() bewerten sollte, die keinen Sinn und sollte macht scheitern, aber PHP wertet es als !($a = foo()), weil es Ausnahmen liebt.

Folgefrage: Was denken Sie, if ($d = $c && $e = $b && $f = $a) tut? https://3v4l.org/3P2hN Ich verstehe es nicht ... Das verstehe ich den zweiten und dritten Fall (mit and), nur nicht das, was im ersten Fall.

+0

PHP Handbuch auch sagen Operator Vorrang und Assoziativität bestimmen nur, wie Ausdrücke gruppiert sind, sie geben keine Reihenfolge der Auswertung. PHP legt (im allgemeinen Fall) nicht fest, in welcher Reihenfolge ein Ausdruck ausgewertet wird und Code, der eine bestimmte Reihenfolge der Auswertung annimmt, sollte vermieden werden, da sich das Verhalten zwischen PHP-Versionen oder abhängig vom umgebenden Code ändern kann. – CY5

+0

@ CY5 Was ist der Unterschied zwischen Gruppierung und Auswertung? Was macht die Gruppierung ohne die Bewertungsreihenfolge? – Rudie

+0

PHP! = JS. Da ist deine Antwort. –

Antwort

13

Nach zend_language_parser.y ist der Code, äquivalent zu $a || ($a = 1) und $a or ($a = 1) jeweils bzw. geparst.

Wie von Melpomene zusammengefasst, sind die Auftragsproduktionen nicht Infix binäre Operatoren über Ausdrücke; eher Zuweisungsoperatoren sind eingeschränkte Produktionen wo die linke Seite eine variable Produktion sein muss.

Per a borrowed quote:

So PHP den Ausdruck in der einzig möglichen Weise analysiert ..

Die Dokumentation ist richtig über den Vorrang .. wo sie gilt.


So folgt die (umgekehrt) Produktionen:

variable "||" variable "=" expr 
variable "||" expr_without_variable 
expr "||" expr 
expr 

Der Fall von !$a = foo() ähnlich ist, und wird als !($a = foo()) nach Durchführung der (umgekehrt) Produktionen geparst:

"!" variable "=" expr 
"!" expr_without_variable 
"!" expr     
expr 

Nun, wie wäre es mit $d = $c && $e = $b && $f = $a? Es ist nicht geparst als ($d = $c) && .., obwohl die &&hat eine höhere Priorität als die Zuordnung. Es wird tatsächlich als $d = ($c && ($e = ..)) usw. geparst, um vom schlauen Leser vervollständigt zu werden.

Während es nicht beiläufig bemerkt, dieser Unterschied ist in der Lage unterschiedliche Ergebnisse produzieren:

$a = (($c = 1) && ($d = 0)); 
var_dump($a, $c, $d);   // => false, 1, 0 

$b = ($e = 1 && $f = 0);  // => $b = ($e = (1 && ($f = 0))); 
var_dump($b, $e, $f);   // => false, false, 0 

Parenthesis sollte daher in der Regel verwendet werden, wenn Zuweisungsoperatoren mit den Betreibern von höheren Vorrang Mischen, vor allem, wenn das Ergebnis einer solchen kann .. unklar sein.

So inkonsequent dies zunächst erscheinen mag, es ist eine gut definierte Grammatik - aber die technischen Details sind hinter etwas Laien Dokumentation begraben; und die Regeln unterscheiden sich subtil von denen in anderen C-Syntax-ähnlichen Sprachen. Das Fehlen eines offiziellen EBNF in der Dokumentation hilft nicht.


Trotz der Parsing-Details, die $a || $a = .. Code (die ist gültig und gut definierte Syntax) sollte aus einer Auswertung Sicht wie die linke Seite des ‚oder‘ dem Stand erfolgen muß gut definierten bleiben rechts wegen guaranteed short-circuiting.


Für dagegen in JavaScript wird a || a = 1 als (a || a) = 1 analysiert - die auch syntaktisch 'gültig' Code ist - gemäß der ECMAScript Grammar Rules. a || a liefert jedoch keinen gültigen Referenzspezifikationstyp, und daher wird Laufzeit ReferenceError ausgelöst.

+1

Laut dieser Grammatik ist '=' kein echter Infix-Operator: Egal, was links davon steht, es wird nur eine Variable erfasst. Es verhält sich wie ein Meta-Präfix-Operator: '$ foo =' analysiert wie ein Präfix-Operator für alle Variablen '$ foo'. – melpomene

+0

@melpomene Das ist der Kern: Die linke Seite eines '=' ist auf eine Variable (im Gegensatz zu einem Ausdruck) beschränkt. – user2864740

+0

Also haben PHP und JS sehr ähnliche Operator-Vorrangregeln, nur unterschiedliche Syntaxregeln? Das macht Sinn. Ich war zu sehr auf dem Präzedenztisch aufgehängt. Vielen Dank! – Rudie

1

Was Ihre followup Frage: if ($d = $c && $e = $b && $f = $a) ist die gleiche wie:

$d = $c; 
if($d) { 
    $e = $b; 
    if($e) { 
     $f = $a; 
     if($f) { 
      ... 
     } 
    } 
} 

Ich nehme an, Sie wissen das, aber einige der Fragen sind mir verwirrend, also werde ich es erwähnen ... = ist ein Zuweisungsoperator, kein Vergleichsoperator. if($a = $b) überprüft nicht, ob $ a und $ b gleich sind, es macht $ a gleich $ b und überprüft dann, ob $ a zu true ausgewertet wird. if($a == $b) überprüft, ob die beiden Variablen identisch sind.

+1

Warum wird es so geparst? Gemäß der Präzedenztabelle sollte es sein: $ d = (($ c && $ e) = (($ b && $ f) = $ a)) '. – melpomene

+0

Meine Vermutung ist der gleiche Grund, dass '" 1 "+ 1 + 1.5" 3.5 ergibt, anstatt Fehler beim Versuch, eine Zeichenfolge und eine ganze Zahl und einen Gleitkommawert hinzuzufügen, zu werfen.PHP ist eine Skriptsprache und (als Antwort) relativ fehlerverzeihend. PHP wertet das && vor dem = nicht aus, weil es in einer if-Anweisung steht und das keinen Sinn (oder weniger Sinn) ergibt. In der Tat wird es nicht einmal die zweite oder dritte Option auswerten, wenn die erste falsch auswertet (weshalb in Ihrem Beispiel $ e und $ f -1 bleiben). Wenn Sie so weit in der genauen Reihenfolge der Auswertung sind, schlage ich vor, auf Klammern zu setzen: Sie sind zuverlässiger. – Stevish

+0

Ich habe meinen cod-Block bearbeitet, um genauer zu reflektieren, wie PHP '=' und '&&' in einer if-Bedingung behandelt. – Stevish

-1

Der Ausdruck ist $a || $a = 1; entspricht dies:

if ($a != true) { 
    $a = 1; 
} 

Eine sehr häufige Variante auf der Idee, für arme-Mans-Debugging verwendet wird:

$debug = true; 

// Thousands of lines of code 

$debug && printf("Foo: {$foo}"); 

// More code 

$debug && printf("Bar: {$bar}"); 

In diesem Paradigma nur die $debug Aussage Bedürfnisse auf "wahr/falsch" gesetzt werden, um das Debugging zu aktivieren/deaktivieren. Ich befürworte diese Art von Debugging nicht, aber ich habe es schon einige Male gesehen.

+1

Bitte antworten Sie auf die OPs Punkte: welche anzeigen, dass es * nicht * so geparst ist. Außerdem ist '||' logisch * nicht * dasselbe wie '&&'. – user2864740

+0

(Nun, "sollte nicht" eher.) – user2864740

+1

Ihr allererster Codeblock ist falsch: 'if ($ a == true) {'. Du meinst "falsch". Und ich weiß das. Beantwortet meine Frage aber überhaupt nicht. – Rudie

Verwandte Themen