Press "Enter" to skip to content

An Exception to PHP's Operator Precedence

Today I saw a question on Lao Wang's tech notes:

<?php
if ($a = 100 && $b = 200) {
	var_dump($a, $b);
}

What's the output?
At first glance this might look simple, but on closer inspection it really isn't.
You might say the part before the boolean AND is just a precedence issue — but if it were purely about precedence, the result would be:

$a = (100 && $b) = 200

In reality, though, the higher-precedence && yields to the lower-precedence =, letting $b = 200 bind first.
The reason is that PHP does not strictly follow the precedence definitions, as the PHP manual itself notes:

Note: 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 of foo() is put into $a.

I won't pass judgement on such a design. In C, at any rate, a similar statement is a syntax error. PHP's choice here is very likely for historical reasons.
The curious will want to know exactly why. A reader, jayeeliu, asked about this before too:

Hello laruence:
I have a question about PHP operator precedence.
$t == 1 && $tt = 2
According to PHP's operator precedence this should execute as
(($t == 1) && $tt) = 2
but in practice it should be
($t == 1) && ($tt = 2)
I don't quite understand this.

Actually it's simple. Operator precedence is a means of choosing between reduction rules when the grammar is ambiguous. But in PHP's grammar definition, there is no reduction conflict between the assignment operator and T_BOOLEAN_AND (&&) in the first place:

expr_without_variable:
  // There's an implicit rule here, effectively making T_BOOLEAN_AND a "unary operator".
  |   expr T_BOOLEAN_AND  { zend_do_boolean_and_begin(&$1, &$2 TSRMLS_CC); } expr

Finally, by the way: alongside T_BOOLEAN_AND, PHP also defines T_LOGICAL_AND (and) and T_LOGICAL_OR (or). Both of these have lower precedence than assignment, which is where the classic line from so many PHP beginner tutorials comes from:

$result = mysql_query(*)  or die(mysql_error());

Similarly, or can be used to emulate the ternary operator (?:):

	$person = $who or $person = "laruence";
//equivalent to:
	$person = empty($who)? "laruence" : $who;

Be First to Comment

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.