Reputation: 21
if (true && 1 == $x = 1 && $x) {
echo "Hello world!";
}
I get an Undefined Variable Notice for $x. Shouldn't the parser know $x at this point, because it solves the If-Clause from left to right?
Upvotes: 0
Views: 126
Reputation: 61935
The observed behavior is due to how the expression is parsed. The following
if (1 == $x = 1 && $x) {
echo "Hello world!";
}
results in an "Undefined variable: x" and does not echo, but
if (1 == ($x = 1) && $x) {
echo "Hello world!";
}
"works" and emits Hello world! as expected.
This is because the former is equivalent to
if (1 == ($x = (1 && $x))) {
echo "Hello world!";
}
and the use of $x is inside the expression that will be used for the assignment. Since this is evaluated before the assignment takes effect, $x is still an "undefined variable" according to PHP.
Solutions:
Although operator precedence is the primary scapegoat, the first form is not equivalent to (1 == $x) = (1 && $x)
which is the derivation when directly following the precedence table. If it were parsed in such a manner it would result in a "syntax error, = unexpected".
This parsing is a quirk of PHP and differs from C grammar rules. (The YACC rules for PHP can be found in zend_language_parser.y.)
PHP: 1 && $x = 2
-> 1 && ($x = 2)
, as per the above stated equivalency. This happens even though &&
is stated to have a higher precedence.
C: 1 && x = 2
-> (1 && x) = 2
, invalid syntax: "lvalue required as left operand of assignment". In C, the &&
operator really does have higher precedence in an expression.
This same behavior is evident when replacing &&
with ==
: despite an assignment having a lower documented priority, the simple precedence table is misleading and inaccurate when assignments are part of expressions.
In conclusion, $x = expr
as part of an expression is parsed equivalently to ($x = (expr))
where expr
can itself be a complex expression containing operators and other expressions.
Upvotes: 1