mofaskyyy
mofaskyyy

Reputation: 21

"Undefined variable" when used after assignment in an if-clause

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

Answers (1)

user2864740
user2864740

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:

  • Use parenthesis as shown; or,
  • Avoid variable assignments in conditional expressions, which I recommend.

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

Related Questions