(PHP has ||
and OR
. JS only has ||
.)
JS. According to MDN ||
has higher precedence than =
. So this doesn't work:
a || a = 1;
because it's evaluated as:
(a || a) = 1;
which results in an "Invalid left-hand side in assignment". I understand that. That makes sense.
PHP. According to PHP.net it works the same for PHP: ||
before =
. However, I use this all the time:
$a || $a = 1;
Why does it work in PHP?? And to top it off: PHP's OR
has lower precedence than =
, so these shouldn't do the same:
$a || $a = 1;
$a OR $a = 1;
but they do... https://3v4l.org/UWXMd
I think JS' ||
works according to MDN's table, and PHP's OR
works like PHP's table, but PHP's ||
shouldn't work like it does.
Is this yet another weird PHP quirk?
The manual also mentions this:
Although
=
has a lower precedence than most other operators, PHP will still allow expressions similar to the following:if (!$a = foo())
, in which case the return value offoo()
is put into$a
.
The precedence table dictates PHP should evaluate (!$a) = foo()
, which makes no sense and should fail, but PHP evaluates it as !($a = foo())
, because it loves exceptions.
Follow-up question: What do you think if ( $d = $c && $e = $b && $f = $a )
does? https://3v4l.org/3P2hN I don't get it... I do understand the second and third case (with and
), just not what happens in the first.
The precedence of an operator specifies how "tightly" it binds two expressions together. For example, in the expression 1 + 5 * 3 , the answer is 16 and not 18 because the multiplication ("*") operator has a higher precedence than the addition ("+") operator. Parentheses may be used to force precedence, if necessary.
The logical-AND operator ( && ) has higher precedence than the logical-OR operator ( || ), so q && r is grouped as an operand.
Certain operators have higher precedence than others; for example, the multiplication operator has higher precedence than the addition operator. Here, operators with the highest precedence appear at the top of the table, those with the lowest appear at the bottom.
In the United States and in France, the acronym PEMDAS is common. It stands for Parentheses, Exponents, Multiplication/Division, Addition/Subtraction. PEMDAS is often expanded to the mnemonic "Please Excuse My Dear Aunt Sally" in schools.
According to zend_language_parser.y the code is parsed equivalently to $a || ($a = 1)
and $a or ($a = 1)
in each case, respectively.
As summarized by melpomene, the assignment productions are not infix binary operators over expressions; rather assignment operators are restricted productions where the left-hand side must be a variable
production.
Per a borrowed quote:
Thus PHP parses the expression in the only possible way..
The documentation is correct about the precedence .. where it applies.
Thus $a || $a = 1
follows the (reversed) productions of:
variable "||" variable "=" expr
variable "||" expr_without_variable
expr "||" expr
expr
The case of !$a = foo()
is similar and is parsed as !($a = foo())
after following the (reversed) productions:
"!" variable "=" expr
"!" expr_without_variable
"!" expr
expr
Now, how about $d = $c && $e = $b && $f = $a
? It is not parsed as ($d = $c) && ..
even though the &&
does have a higher precedence than the assignment. It is actually parsed as $d = ($c && ($e = ..))
and so on, to be completed by the astute reader.
While it might not be casually noticed, this difference is capable of producing varying results:
$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 should thus generally be used when mixing assignment operators with operators of higher precedence, especially when the result of such may be .. unclear.
As inconsistent as this may initially seem, it is a well-defined grammar - but the technical details are buried behind some fairly layman documentation; and the rules differ subtly from those in other C-syntax-like languages. The lack of an official EBNF in the documentation doesn't help.
Despite the parsing details, the $a || $a = ..
code (which is valid and well-defined syntax) should remain well-defined from an evaluation viewpoint as the left side of the 'or' must occur prior to the right due to guaranteed short-circuiting.
For contrast, in JavaScript, a || a = 1
is parsed as (a || a) = 1
- which is also syntactically 'valid' code - per the ECMAScript Grammar Rules. However, a || a
does not yield a valid Reference Specification Type and thus a runtime ReferenceError is thrown.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With