PHP中的评估顺序

译者注。Nikita Popov为PHP语言的发展做出了并将继续做出巨大贡献。他非常了解PHP引擎的内部原理,在本文中,他根据表达式求值的顺序解释了PHP的一些功能,这些表达式可能在任何地方都找不到。这篇文章大约有7年历史了,实际上并没有失去它的相关性,但是,很难找到它,因为它不在Nikita Popov的博客中,而是在gis-s的github上发布的。我认为将其呈现给俄语社区会很有用。



在我最喜欢的reddit社区lolphp中,我遇到了一个帖子,人们对以下代码的结果感到惊讶:



<?php

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

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


如您所见,表达式($a + $a++)($a + $a + $a++)给出相同的结果,这是非常意外的。这里发生了什么?



运算符优先级和关联性



许多人认为,对表达式求值的顺序由运算符优先级和关联性决定,但事实并非如此。优先级和关联性仅确定表达式中操作分组的顺序。

在第一个表达式中,$c = $a + $a++;后递增“ ++”优先于“ +”,因此$ a ++是一个单独的组:



$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. 操作员@禁用CV优化并因此降低性能。原则上,操作员@不利于性能。


尼克



译者注:如前所述,它@仅在5.x中禁用CV优化,在PHP 7中,即使使用了错误抑制运算符,也会进行CV优化(但可能并非在所有情况下都如此)。Nikita Popov有一篇有趣的博客文章,《PHP 7中的静态优化》,以防有人想深入研究优化主题。




All Articles