RJ博客

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++具有相同的结果,在这一点上,很多人认为表达式的评估顺序由运算符优先级和关联性决定。但这不是真的。优先级和关联性只能告诉你表达式是如何分组的:

//在第一个表达式
$a + $a++ ; 
//“++”的优先级高于“+”,所以“$a++”被分组:
$a +($a++);

//在第二个表达式
$a + $a + $a++ ; 
//“++”的优先级高于“+”:
$a + $a +($a++); 
//和“+”是左关联运算符,所以左“+”分组:
($a + $a)+($a++);


让我们看看两个代码片段生成的操作码。

我们从头开始$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操作码中被读取。


让我们试试看。我们$a + $a++再次使用该表达式,但是这个时候在@之前添加一个表达式:

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

当出现误差抑制算子时,结果变成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

总结:

  1. 正常情况下PHP将评估left-to-right,访问简单的变量将在更复杂的表达式之后执行,而不管表达式实际发生的顺序如何。

  2. 在复杂表达式之后提取简单变量的原因是编译变量(CV)优化。

  3. 如果禁用此优化,例如通过使用@错误抑制算子,所有表达式都将被评估为left-to-right,包括简单变量提取。




REF:

https://gist.github.com/nikic/6699370

https://gxnotes.com/article/52966.html

https://github.com/xurenlu/phplearn/blob/master/%E4%B8%80%E4%B8%AAPHP%20bug%E5%BC%95%E5%8F%91%E7%9A%84%E6%8E%A2%E7%B4%A2.md

https://stackoverflow.com/questions/9709818/why-is-a-a-2

https://3v4l.org/HGIE3#output



相关推荐

发表评论