(PHP has ||
and OR
. JS only has ||
.)
JS. According to MDN ||
has higher precedence than =<
The expression $a || $a = 1;
is equivalent to this:
if ( $a != true ) {
$a = 1;
}
A very common variant on the idea is used for poor-mans debugging:
$debug = true;
// Thousands of lines of code
$debug && printf("Foo: {$foo}");
// More code
$debug && printf("Bar: {$bar}");
In this paradigm, only the $debug
statement needs to be set to true/false to enable/disable debugging. I'm not advocating this type of debugging, but I've seen it quite a few times.
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.
As to your followup question: if ( $d = $c && $e = $b && $f = $a )
is the same as:
$d = $c;
if($d) {
$e = $b;
if($e) {
$f = $a;
if($f) {
...
}
}
}
I assume you know this, but some of the questions are confusing to me, so I'll mention it... = is an assignment operator, not a comparison operator. if($a = $b)
doesn't check if $a and $b are the same, it makes $a equal $b, then checks if $a evaluates to true. if($a == $b)
checks if the two variables are the same.