Reputation: 41
I am reading the Operator Precedence section of the PHP Manual. I am confused about (or say, I don't understand the following sentences quite much):
Operator precedence and associativity only determine how expressions are grouped, they do not specify an order of evaluation. PHP does not (in the general case) specify in which order an expression is evaluated and code that assumes a specific order of evaluation should be avoided, because the behavior can change between versions of PHP or depending on the surrounding code.
It also gives two examples to illustrate the undefined order of evaluation.
<?php
$a = 1;
echo $a + $a++; // may print either 2 or 3
>?
From what I understand, $a evaluats to 1 first because the associativity of the addition operator is left. Then 1 is added to $a++, which evaluates to 1. So, then result should be 2. Why does the comment in the documentation say "may print either 2 or 3"?
The second example is:
<?
$i = 1;
$array[$i] = $i++; // may set either index 1 or 2
?>
Similarly, $i++ evaluates to 1 first because the associativity of the assignment operator is right. Then the value of 1 should be set to the index 2 of the array. Why does the comment say "may set either index 1 or 2"?
The only explanation I can think of is that the order of code in the two examples above can be executed the opposite of what I reasoned.
Any thoughts to help me unravel my confusion will be greatly appreciated.
Upvotes: 3
Views: 664
Reputation: 350137
The confusion concerns associativity. Where you say it applies there is no associativity at play.
Look at the given examples:
$a = 1;
echo $a + $a++; // may print either 2 or 3
You can break down the evaluation of that expression in two steps:
$a
and calculate $a++
The precedence rules have something to say about this:
$a++
should happen before the evaluation of the addition:++
has higher precedence than +
But that is it.
There is no rule that says that the value of $a
should be retrieved before $a++
is evaluated. That is not what left associativity is about.
Left (or right) associativity only comes into play when two operators with the same precedence (e.g. twice the same operator) occur one after the other in one expression. For instance
$a = 0
$a++ - 1 - $a++
The first -
is guaranteed to be executed before the second, by the left associativity rule.
But, this leaves open the possibility for the following sequence of evaluation:
$a++
$a++
So, although the associativity rule fixed that step 4 had to come after step 3, there is no rule that dictates the order of the first two steps.
$i = 1;
$array[$i] = $i++; // may set either index 1 or 2
Again, there is no left associativity at play here. PHP is free to perform the following two steps in either order:
$i++
$i
for the indexThere is no rule that dictates in which order this should happen.
Right associativity would be at play if the statement was like this:
$i = 1;
$array[$i] = $i = $i + 1; // may set either index 1 or 2
Now PHP has to execute the following steps, with some freedom in the order of them:
$i
$i
in the middle, yielding its value$i
for the indexAssociativity wants steps 3 and 6 to be in that order. It is not allowed that the array element receives its value before the "middle" $i
does. But it does not prevent PHP from going for this alternative:
$i
for the index$i
$i
in the middle, yielding its valueAs steps 5 and 6 are still in the correct order, the associativity rule is abided by. Still the result is different.
Left associativity would also be at play if the statement was like this:
$array[$i][$j] = $i++;
It is quite trivial, but the left associativity rule for [
means that first the left-most index is used to retrieve an element from the array, and only then the second index should be used on the resulting array. But note that this still does not mean that $i
has to be evaluated before $j
.
Take this variation:
$i = 1;
$array[$i++][$i] = 13;
You cannot assume that the element $array[1][2]
will get the value 13. It might well be $array[1][1]
. Left associativity says nothing about this. It does state however that the retrieval of array elements (in this construct) must be done from left to right.
In steps, this is a possible scenario:
$i
is evaluated: 1$i++
is performed and yields 1Step 3 and 4 have to happen in that order. They don't even have to be adjacent steps. This also is allowed for PHP to do:
$i++
is performed and yields 1$i
is evaluated: 2Step 2 occurs before step 4, so the associativity rule is not broken.
Even though the statement at hand from Operators Precedence seems to be warranted, that article has at least one error concerning precedence, as I have elaborated in answer to this question.
Upvotes: 3
Reputation: 780798
Just because an operator is left-associative, it doesn't mean the parameters are evaluated left-to-right. In
$a + $a++
It can evaluate $a
first or $a++
first. In the first case, the result is 1 + 1 = 2
; in the second case the result is 2 + 1 = 3
.
Associativity just specifies how multiple expressions are grouped when they're combined. For instance, if you have
1 - 2 + 3
left-associativity specifies that this is interpreted as
(1 - 2) + 3 = 2
rather than
1 - (2 + 3) = -4
But if this expression had sub-expressions with side effects, it could still evaluate them right-to-left (or in some mixed order).
Upvotes: 1