Skip to content

Instantly share code, notes, and snippets.

@yantze
Last active August 18, 2016 11:06
Show Gist options
  • Save yantze/981ab48d4e7c7723e89898c4a111f616 to your computer and use it in GitHub Desktop.
Save yantze/981ab48d4e7c7723e89898c4a111f616 to your computer and use it in GitHub Desktop.
php 奇怪的自增和运算符执行顺序分析 some weird evaluation about post_inc and pre_inc

php 奇怪的自增和运算符执行顺序分析

查看在线执行结果: https://3v4l.org/HFmA7

要想了解下面代码的结果,有三点需要了解:

  • ++$a 是自己加1,之后的都要加1;如果是指针引用,有些版本会导致 ++$a 的临时值为自身,让之前的计算结果也改变。
  • $a++ 是自己不用增1的结果,但是这个操作符之后的都要加1,不管有没有指针引用。
  • 编译器每一次都要把表达式组合成两元组:((($a++ + $a) + $a) + $a),但是在 ($a + $a++) 的情况下,会改变顺序为 ($a++ + $a),所以 $a++ + $a 的结果是3.

下面是 $a = 1; $b = &$a; echo ++$a + ++$a + $a;的 vld 编码,可以看出具体的流程。

(php v7.0)
compiled vars:  !0 = $a, !1 = $b
line     #* E I O op                           fetch          ext  return  operands
-------------------------------------------------------------------------------------
   2     0  E >   ASSIGN                                                   !0, 1
   3     1        ASSIGN_REF                                               !1, !0
   4     2        PRE_INC                                          $4      !0
		 3        PRE_INC                                          $5      !0
		 4        ADD                                              ~6      $4, $5
		 5        ADD                                              ~7      ~6, !0
		 6        ECHO                                                     ~7
   5     7        ECHO                                                     !0
		 8      > RETURN                                                   1

from: https://3v4l.org/fgLZO/vld#tabs

不同的php 版本不同,导致的结果不同。我用 c++ 测试过,gcc 和 clang 的结果也不同(当然会有warning). ++a;++a, clang 结果是6, gcc 结果是5

总结:

  • 目前hhvm和7.0.0+都不再会受到指针引用的影响。(受影响的版本 5.1.1 - 5.6.24)
  • 混写的写法:不易查错,不易 debug,全语言混乱
  • 建议所有自增尽量用新行写

Refer

<?php
// author: yantze
// date: 2016-07-31
// desc: php 自增和运算符执行顺序分析
// #1
function test1(){
echo PHP_EOL.__function__ .":";
$a=1;
echo (++$a)+(++$a);
}
test1(); // 5
// #2
function test2(){
echo PHP_EOL.__function__ .":";
$a=1;
$b=&$a;
echo (++$a)+(++$a);
}
test2(); // 6(5.1.1 - 5.6.24) or 5(hhvm, 7.0.0+)
// #3
function test3(){
echo PHP_EOL.__function__ .":";
$a=1;
$b=&$a;
echo (++$a)+(++$a)+(++$a);
}
test3(); // 10(5.1.1 - 5.6.24) or 9(hhvm, 7.0.0+)
// #4
function test4(){
echo PHP_EOL.__function__ .":";
$a=1;
// $b=&$a;
echo $a + $a++;
}
test4(); // 3
// #5
function test5(){
echo PHP_EOL.__function__ .":";
$a = 1;
// $b = &$a;
// echo @$a + $a++; // 2
echo $a + $a++; // 3
}
test5(); // 3
// #6
function test6(){
echo PHP_EOL.__function__ .":";
$a = 1;
echo $a + $a + $a++;
}
test6(); // 3
// four quiz
function quiz() {
echo PHP_EOL.__function__ .":";
$a=1;
$b=&$a;
echo ($a++)+(++$a);
$a=1;
$b=&$a;
echo (++$a)+($a++);
$a=1;
//$b=&$a;
echo (++$a)+($a++);
$a=1;
$b=&$a;
echo (++$a)+(++$a);
}
quiz();
// answer: 4445(hvvm,7.0.0+) 4556(4.3.0 - 5.6.24)
// Good points from above
// #0.1
// $a = -1;
// var_dump($a && true); // true
// var_dump($a && false); // false
// var_dump($a && -1); // true
// #0.2
// $a + $a + $a + $a + $a
// + is left-assoc, so it's grouped as
// (((($a + $a) + $a) + $a) + $a)
// #0.3
// $a + $a + $a + $a + $a
// $a = $b = $c = $d = $e
// = is right-assoc, so it's grouped as
// ($a = ($b = ($c = ($d = $e))))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment