65

If I try this:

$a = 0;    
echo $a + ++$a, PHP_EOL;
echo $a;

I get this output:

2
1

Demo: http://codepad.org/ncVuJtJu

Why is that?

I expect to get this as an output:

1
1

My understanding:

$a = 0;                    // a === 0    
echo $a + ++$a, PHP_EOL;   // (0) + (0+1) === 1
echo $a;                   // a === 1

But why isn't that the output?

hakre
  • 193,403
  • 52
  • 435
  • 836
Naftali
  • 144,921
  • 39
  • 244
  • 303
  • 23
    Whatever you intended `$l + ++$l` to mean, I guarantee that there's a more straightforward way to express that intent. – Keith Thompson Mar 15 '12 at 07:10
  • 1
    as a side note: this is an example of question that Andi Gutmans sometimes use in conference. This is the expected behaviour in php as stated before by other users as ++$l is evaluated before the rest of the expression. – malko Mar 21 '12 at 09:42

13 Answers13

115

All the answers explaining why you get 2 and not 1 are actually wrong. According to the PHP documentation, mixing + and ++ in this manner is undefined behavior, so you could get either 1 or 2. Switching to a different version of PHP may change the result you get, and it would be just as valid.

See example 1, which says:

// mixing ++ and + produces undefined behavior
$a = 1;
echo ++$a + $a++; // may print 4 or 5

Notes:

  1. Operator precedence does not determine the order of evaluation. Operator precedence only determines that the expression $l + ++$l is parsed as $l + (++$l), but doesn't determine if the left or right operand of the + operator is evaluated first. If the left operand is evaluated first, the result would be 0+1, and if the right operand is evaluated first, the result would be 1+1.

  2. Operator associativity also does not determine order of evaluation. That the + operator has left associativity only determines that $a+$b+$c is evaluated as ($a+$b)+$c. It does not determine in what order a single operator's operands are evaluated.

Also relevant: On this bug report regarding another expression with undefined results, a PHP developer says: "We make no guarantee about the order of evaluation [...], just as C doesn't. Can you point to any place on the documentation where it's stated that the first operand is evaluated first?"

interjay
  • 107,303
  • 21
  • 270
  • 254
  • Yea, it's because the expression is evaluated from right to left in the parser. But as long as that is not specified the behavior of the expression is not specified and should be avoided. – Tarion Mar 15 '12 at 12:51
  • How does the *"assignments are parsed in a right to left order"* rule of [PHP expressions](http://php.net/manual/en/language.expressions.php) does not shed some light into this? Won't it remove the undefined behaviour? – hakre Mar 16 '12 at 12:07
  • @hakre: That rule just says that assignment is right-associative, i.e. `$a=$b=$c` is parsed as `$a=($b=$c)`. It is only relevant when you have multiple assignment operators in an expression. – interjay Mar 16 '12 at 12:31
  • @interjay: But for the expression asked about, the left part is not involved in any incrementation. As the right part is triggered first because of operator precedence, it's not undefined. Edit: Well actually you can't say, right. – hakre Mar 16 '12 at 12:40
  • 2
    @hakre: The right part is not necessarily evaluated first. Operator precedence only determines where to add the parentheses here, i.e. `$l + ++$l` --> `$l + (++$l)`. But it does not determine whether the left or right side of the `+` operator is evaluated first. – interjay Mar 16 '12 at 12:46
  • @interjay: Yes, I edited the comment, after writing it, it popped into my mind that it generally can not be said as it's unknown which part is evaluated first. Well actually right now, the right part is evaluated first, but I have not found this specified in the manual somewhere so I can't say it will ever be. It's only predictable but not specified. – hakre Mar 16 '12 at 12:48
  • The result doesn't seem to be as volatile as this answer implies - [As early as 4.3.2](http://3v4l.org/fbQo4), this expression evaluates to 4. – nickb Jul 01 '12 at 02:57
  • This answer does not say it is volatile behaviour. It is likely that the same PHP implementation will always return the same result. But which result that might be is not specified, and so is simply undefined. The implication being that behaviour CAN change depending on implementation, version, and potentially even context. You just won't ever KNOW any GUARANTEES. – MatBailie Sep 30 '12 at 16:21
  • Is this answer still valid for PHP 7? It seems now parser will always do increment/decrement operations first so if $a = 0; then $a + $a++ means 0 + 1 and $a + ++$a means 1 + 1. – Sharak Nov 07 '20 at 23:34
  • @Sharak The documentation is clear that this is still undefined. Just because you got some result in a test doesn't mean you should rely on it. – interjay Nov 08 '20 at 08:05
66

A preincrement operator "++" takes place before the rest of the expression it's in evaluates. So it is actually:

echo $l + ++$l; // (1) + (0+1) === 2
Czechnology
  • 14,832
  • 10
  • 62
  • 88
Dennis
  • 2,607
  • 3
  • 21
  • 28
  • 8
    To add to this: Compare against `echo $l + $l++;`, which outputs `1` as the OP was expecting. –  Mar 14 '12 at 20:39
  • 2
    Side note; is that actually documented for PHP? I can't find anything about its evaluation order vs. the rest of the expression. – Joachim Isaksson Mar 14 '12 at 20:42
  • ... In the link posted 3 comments up – Corbin Mar 14 '12 at 20:47
  • To add some more: This is the same as in C, and probably any language that implements the preincrement operator - which is the correct way to implement this operator. Also equivalent to `$l + ( $l = $l + 1 )`. – kitti Mar 14 '12 at 20:47
  • 1
    @JoachimIsaksson Yes, it is documented as undefined behaviour. @RyanP No, there're languages with defined behaviour in such cases, e.g. `Java`. – kirilloid Mar 14 '12 at 20:50
  • 3
    @Corbin Operator precedence does not really explain the evaluation order, since postfix and prefix ++ both have the same precedence but aren't evaluated in the same order. – Joachim Isaksson Mar 14 '12 at 20:51
  • @kirilloid Undefined I can buy, was just trying to figure out if it was something to depend on like in Java or undefined as in C. – Joachim Isaksson Mar 14 '12 at 20:53
  • @JoachimIsaksson If I understand it correctly, they are *theoretically* evaluated in the same order. That's why $i = $i++ + ++$i is undefined behaviour (in C/C++/PHP/...). With $i = $i + ++$i; ++ is higher precedence than +, so the ++ is evaluated and then the + is evaluated. Unless I'm misunderstanding your question? – Corbin Mar 14 '12 at 20:54
  • @Neal that enters the land of undefined behaviour. – Corbin Mar 14 '12 at 20:55
  • @RyanP: No this is *not* the same as in C. In C this is undefined behaviour, because the order of evaluation of sub-expressions relative to each other is unspecified, and so the reading of `l` in `l` and the writing of `l` in `++l` are unsequenced relative to each other. – Mankarse Mar 14 '12 at 20:57
  • @RyanP: It's definitely not the same in C. See the [code](http://codepad.org/W5k5mpwJ) – ypercubeᵀᴹ Mar 14 '12 at 20:59
  • @kirilloid What about your answer? It's partially wrong and partially correct. But other than that, what am I looking for? (It's correct in that it's not equivalent to the code you posted, and it's wrong in that it is stored in a 'temporary anonymous variable' just not at the PHP level -- and yes, that's really only wrong if you're being very picky.) – Corbin Mar 14 '12 at 21:00
  • @ypercube Yes it is. I tested before I posted that. `int a = 0; int c = a + ++a; printf("%d\r\n",c);` => prints '2', same as PHP. – kitti Mar 14 '12 at 21:01
  • @Corbin would it be wrong, it would work another way and result in `1`. – kirilloid Mar 14 '12 at 21:03
  • @kirilloid Not sure what you mean? – Corbin Mar 14 '12 at 21:04
  • 8
    @RyanP: See [Undefined behaviour](http://stackoverflow.com/questions/949433/could-anyone-explain-these-undefined-behaviors-i-i-i-i-i-etc) – ypercubeᵀᴹ Mar 14 '12 at 21:08
  • @Dennis: I added another, [very similar question](http://stackoverflow.com/questions/9710604/why-is-0-1-2-continued) – ypercubeᵀᴹ Mar 14 '12 at 21:34
  • That sucks. Seems like a flaw in the language. – Andy Ray Mar 15 '12 at 06:54
  • `++$a: Pre-increment--Increments $a by one, then returns $a.` and it does not takes place before rest of the expression but in the order dictated by operator precedence. – Salman A Jan 01 '13 at 19:23
24
a + b

a = 1
b = ++a

:= 2

Why do you expect something else?

In PHP:

$a = 0;
$c = $a + ++$a;

Operator precedence visualized:

$c = ($a) + (++$a);

Evaluation sequence visualized:

$a = 0; ($a = 0)
$a = 1; (++$a)
$c = $a + $a (1 + 1);

Or written out:

The moment the sum operation is performed, $a is already 1 because ++$a has been already evaluated. The ++ operator is evaluated before the + operator.


For the fun:

$a++ + ++$a

Results in 2, too. However if you compare it as an expression, it's not equal:

$a++ + ++$a == $a + ++$a

Where as

$a++ + ++$a == $a-- + --$a 

is "equal".


See Also:

Community
  • 1
  • 1
hakre
  • 193,403
  • 52
  • 435
  • 836
  • 3
    @hakre you need to explain this, your answer doesn't make sense. – Toby Allen Mar 14 '12 at 20:35
  • Yeah, a = 1 because when b is evaluated, a is 1 and not 0. Was not really clear for everybody, I edited the answer. And for the fun, I added some bonus expressions at the end. – hakre Mar 14 '12 at 20:56
  • @hakre: I added another, [very similar question](http://stackoverflow.com/questions/9710604/why-is-0-1-2-continued) – ypercubeᵀᴹ Mar 14 '12 at 21:34
  • @hakre OT: Your print_r converted is .. broken. Care to fix your link ? – Martin. Apr 06 '12 at 10:39
  • @Martin.: It was based on codepad viper but codepad viper changed. You can find the source here: https://gist.github.com/1102761 – hakre Apr 06 '12 at 10:44
  • @hakre yeah I've spotted that. Wait, every codepad viper entry was deleted? – Martin. Apr 06 '12 at 10:59
7

My Evaluation Order in PHP blog post explain this in detail, but here is the basic idea:

  • Operator precedence and associativity have nothing to do with evaluation order.
  • PHP does not guarantee an evaluation order. The order can change between PHP versions without notice and can also be different depending on the surrounding code.
  • "Normally" PHP will evaluate left-to-right, with the exception of accesses to "simple" variables (like $a). Accesses to simple variables will be executed after more complex expressions, regardless in which order the expressions actually occur.
  • In this particular case it means that ++$a is run first because it is a complex expression and only then the value of $a is fetched (it is already 1 at this point). So effectively you are summing 1 + 1 = 2.
  • The reason that simple variables are fetched after complex expressions is the Compiled Variables (CV) optimization. If you disable this optimization, for example by using the @ error suppression operator, all expressions are evaluated left-to-right, including simple variable fetches.
  • In this particular case it means that @($a + ++$a) will result in 1, because first $a is fetched (0 at that time) and incremented only after that.
NikiC
  • 100,734
  • 37
  • 191
  • 225
6

++ is the higher precedence operator, so it gets applied first.

So now l = 1.

So 1 + 1 = 2.

samayo
  • 16,163
  • 12
  • 91
  • 106
John3136
  • 28,809
  • 4
  • 51
  • 69
3

When you do your ++$l (preincrement), it will be done before your addition -> check operator precedence).

So, the value of $l will be 1 before your addition :

echo $l + ++$l; // $l => 1  because ++$l is done first

So your answer will be 2.

But when you do :

echo $l // you will get your first value which is $l => 1

So your answer will be 1.

ChapMic
  • 26,954
  • 1
  • 21
  • 20
2

This behaviour can be confirmed by inspecting how PHP compiles your script, for example:

$a = 0;
echo $a + ++$a;

Compiles into the following opcodes, which are then executed:

compiled vars:  !0 = $a
line     # *  op                           fetch          ext  return  operands
---------------------------------------------------------------------------------
   1     0  >   ASSIGN                                                   !0, 0
         1      PRE_INC                                          $1      !0
         2      ADD                                              ~2      !0, $1
         3      ECHO                                                     ~2
         4    > RETURN                                                   null

This translates to the following equivalent script:

$a = 0;              // ASSIGN
$tmp = ++$a;         // PRE_INC
echo $a + $tmp;      // ADD, ECHO

Conclusion

By the time $a is evaluated as the left hand expression of $a + (++$a), it has already been incremented, because ++$a was evaluated first.

Obviously, this behaviour should not be relied upon; in any language for that matter.

Ja͢ck
  • 170,779
  • 38
  • 263
  • 309
1

The output of your code varies with PHP version as seen here

Output for 4.3.0 - 5.0.5
1
1

In the above case the left hand side of + operator is evaluated first (0, 1, +).

Output for 5.1.0 - 5.5.0alpha4
2
1

In the above case the right hand side of + operator is evaluated first (1, 1, +).

This is in accordance with interjay's answer that in PHP there is no guarantee about the order of evaluation of sub-expresions. The assumption that the output could be 1, 1 is correct, so are that answers that claim that the output could be 1, 2.

Community
  • 1
  • 1
Salman A
  • 262,204
  • 82
  • 430
  • 521
1

Check the increment operator manual:

http://www.php.net/manual/en/language.operators.increment.php

Or see this codepad: http://codepad.org/Y3CnhiLx

<?php

$n = 0;
$m = 0;
echo '++ before:';
echo $n+ ++$n;
echo PHP_EOL;
echo '++ after:';
echo $m+ $m++;
echo PHP_EOL;
echo 'n:'.$n;
echo PHP_EOL;
echo 'm:'.$m;

Outputs:

++ before:2
++ after:1
n:1
m:1
Guumaster
  • 389
  • 3
  • 10
1

As you may know we have two increment operator, one is pre-increment and second is post-increment. Pre-increment increase the value of integer before it use in expression, on the other hand post increment increase value of number after it used in expression.

suppose you have variable $a and variable $b as below

$a=0;

$b=++$a gives the value of b=1

while

$b=$a++ gives the value b=0

kundan bora
  • 3,821
  • 2
  • 20
  • 29
0

First obvious part is that ++ have higher priority than +.

Second part is that php engine doesn't store value from first operand into another anonymous variable. So $l + ++$l is not an qeuivalent for

$a = $l;
$b = ++$l;
return $a + $b;
kirilloid
  • 14,011
  • 6
  • 38
  • 52
  • Sorry but operator priority has nothing to do with this. All answers mentioning operator precedence are incorrect. – Salman A Feb 08 '13 at 13:16
  • So just because of I mentioned operator precedence, my answer become incorrect. Ha-ha, funny. – kirilloid Feb 08 '13 at 13:22
0

As mentioned before there is a difference in x++ and ++x. You can interpret it in the way that

x++;

increments after the semicolon

and

++x;

increments on evaluation of the expression

So it seems that your expression is evaluated from right to left

echo $l + ++$l;
  1. Get $l: $l = 0
  2. Apply ++: ++$l = 1
  3. Get $l: $l = 1
  4. Apply +: $l + $l = 1 + 1 = 2
Tarion
  • 16,283
  • 13
  • 71
  • 107
-2

All statements are executed from right to left. So the value is first incremented than the value of your variable is = 1 so 1+1=2

Fawad Ghafoor
  • 6,039
  • 7
  • 41
  • 53