Evaluation order in PHP

Translator's note. Nikita Popov has made and continues to make a huge contribution to the development of the PHP language. He understands the internals of the PHP engine very well and in this article he explains some of the features of PHP in terms of the order of expression evaluation, which, perhaps, are not particularly found anywhere. This article is about 7 years old and has practically not lost its relevance, however, it is rather difficult to find it, because it is not in Nikita Popov's blog, but it was published in his gist-s on github. I think it will be useful to present it to the community in Russian.



In my favorite Reddit community lolphp I came across a post where people are surprised at the result of the following code:



<?php

$a = 1;
$c = $a + $a++;
var_dump($c); // int(3)

$a = 1;
$c = $a + $a + $a++;
var_dump($c); // int(3)


As you can see, expressions ($a + $a++)and ($a + $a + $a++)give the same result, which is quite unexpected. What's going on here?



Operator precedence and associativity



Many people think that the order in which an expression is evaluated is determined by operator precedence and associativity , but this is not the case. Priority and associativity only determine the order in which operations are grouped in an expression.

In the first expression, $c = $a + $a++;post-increment "++" takes precedence over "+", so $ a ++ is a separate group:



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


$c = $a + $a + $a++; - "++" , "+":



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


"+" - , "+" :



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


: , .



? . , , . , , ($a + $a), ($a++) .



PHP . PHP , — . , - .



CV



-, , PHP , , ( PHP).



(compiled variables, CV), PHP 5.1. (, $a, $a->b $a['b']) . — , PHP , Zend VM ( Zend). 2 .



, .

$a + $a + $a++:



// code:
$a = 1;
$c = ($a + $a) + ($a++);


// opcodes:
         ASSIGN   $a, 1
$tmp_1 = ADD      $a, $a
$tmp_2 = POST_INC $a
$tmp_3 = ADD      $tmp_1, $tmp_2
         ASSIGN   $c, $tmp_3


:



  • $a = 1,
  • — $a + $a $tmp_1,
  • - $a $tmp_2,
  • , , $c.


( $a + $a, $a++), , , .



$a + $a++:



// code:
$a = 1;
$c = $a + ($a++);


// opcodes:
         ASSIGN   $a, 1
$tmp_1 = POST_INC $a
$tmp_2 = ADD      $a, $tmp_1
         ASSIGN   $c, $tmp_2


, POST_INC ($a++) , $a ADD. ? . . CV .



CV



: , CV - @. PHP 5.x, PHP 7 . , PHP 5 , , - - CV CV.



PHP 5.x

() , CV , , @.



. $a + $a++, , @:



<?php

$a = 1;
@ $c = $a + $a++;
var_dump($c); // int(2)


, , 3 2. , :



         ASSIGN        $a, 1
$tmp_1 = BEGIN_SILENCE
$var_3 = FETCH_R       'a'
$tmp_4 = POST_INC      $a
$tmp_5 = ADD           $var_3, $tmp_4
$var_2 = FETCH_W       'c'
         ASSIGN        $var_2, $tmp_5
         END_SILENCE   $tmp_1


, . -, BEGIN_SILENCE END_SILENCE . . -, $a $b FETCH_R ( ) FETCH_W ( ) .



, $a , .






CV , , .



. $a + $a++, :



<?php

$a = [1];
$c = $a[0] + $a[0]++;
var_dump($c); // int(2)


, , 3 2. , :



         ASSIGN        $a, [1]
$tmp_3 = FETCH_DIM_R   'a', 0
$var_4 = FETCH_DIM_RW  'a', 0
$tmp_5 = POST_INC      $var_4
$tmp_6 = ADD           $tmp_3, $tmp_5
         ASSIGN        $c, $tmp_6


, FETCH_DIM_R ( ) FETCH_DIM_RW ( /) .



, , , .



, . 3v4l.org.





- , :



  1. . .
  2. The operator @disables CV optimization and degrades performance as a result. The operator is, @in principle, bad for performance.


~ nikic



Translator's note: as mentioned above, it @disables CV optimizations only in 5.x, in PHP 7 CV optimizations take place even if the error suppression operator is used (but perhaps this does not happen in all cases). Nikita Popov has an interesting blog post, Static Optimization in PHP 7 , in case someone wants to dig deeper into the topic of optimization.




All Articles