$a = 1;
$c = $a + ($a++);
var_dump($c);//3
$a = 1;
$c = (++$a)+$a;
var_dump($c);//4
$a = 1;
$c = (++$a)+($a++);
var_dump($c);//4
$a = 1;
$b = &$a;
$c = (++$a)+($a++);
var_dump($c);//5
求解释。
$c = $a + ($a++);
var_dump($c);//3
$a = 1;
$c = (++$a)+$a;
var_dump($c);//4
$a = 1;
$c = (++$a)+($a++);
var_dump($c);//4
$a = 1;
$b = &$a;
$c = (++$a)+($a++);
var_dump($c);//5
求解释。
1)表达式从左到右执行,所以$a这时还是1,1+2=32)同样是从左到右执行,++$a为2,这时$a已经自加过,所以2+2=43)++$a是先自加,这时$a值为2,后面的$a++是后自加,所以2+2=44)因为是改变引用的值,所以是2+3=5
$c = $a + ($a++);
var_dump($c, $a);//3, 2
$a++ 等价于 $a = $a + 1
所以
$c = $a + ($a++);
等价于
$c = 2 + (1);
根据加法交换律
$c = $a + ($a++);
等价于
$c = ($a++) + $a; //写成这样就不难理解了吧?
等价于
$c = (1) + 2;其他类同
$a = 1;
$c = (++$a)+($a++);
var_dump($c, $a);//4, 3是这么理解的
(++$a) 先加 1,后取值
取出 $a 的值(2)参与运算
($a++) 先取值,后加 1
取出 $a 的值(2)参与运算
$c = (2) + (2)
虽然此时 $a 已经是 3 了
但参与计算的都是标量,没有变量
注意与 1 式的区别
是以变量参与运算的
表示$a先加1,再返回$a值
相当于
$a=$a+1;
返回 $a ; $a++ 表示先返回$a的值再给$a加1返回 $a;
$a=$a+1;
eg:
$a=1;echo $a++; //先返回$a,然后给$a做加1运算 相当于 echo $a; $a=$a+1; 输出是1echo ++$a; // 先给$a做加1运算,再返回$a 相当于 $a=$a+1; echo $a; 输出是2
$a = 1;
$c = (++$a)+($a++);
var_dump($c);//4$a = 1;
$c = ++$a + $a++;
var_dump($c);//4$a = 1;
$c = $a++ + ++$a;
var_dump($c);//4
$a = 1;
$b = &$a;
var_dump($c);//5
由于应用的存在,情况要复杂点由于有一个对 $b 的赋值过程,这相当于
$a = 1;
$c = (++$a)+($b = $a+1);
var_dump($c);//5
++$a则是在执行过程中就改变了$a的值,执行后则不变$b=&$a 导致了$a++做了“执行后”这个动作,所以$a++也递增了我习惯就是这样理解的,也不知是否合适
$a=1;
$c=$a+($a++);
红色的$a是以变量参与运算,但是为什么是2呢? 难道$a+($a++)先运行($a++)部分吗?
测试过去掉$a++的括号结果还是一样,那么跟括号没有关系。那么表达式不是从左往右计算吗?
估计得这么理解function returnFirst(&$a)
{
$return=$a;
$a=$a+1;
return $return;
}function plusFirst(&$a)
{
$a=$a+1;
$return=$a;
return $return;
}
$a=1;
$c=$a+returnFirst($a) ; //$c=$a+(a++)
var_dump($c,$a); //3,2
$c=($a++)+($a++) 要理解成 $c=($b=$a+1)+($b=$a+1)吗?
$c=($a++)+($a++) 返回的结果是3
$c=($a++)+($a++) 要理解成 $c=($b=$a+1)+($b=$a+1)吗?
$c=($a++)+($a++) 返回的结果是3更晕了,听了你的一席话,我又觉得斑竹的解释有问题了
nnd这个问题太折磨人了当$b=&$a,好像只有在(++$a)在运算表达式的最左边才会出意外的状况。
即:
(++$a)+表达式2+表达式3......
注:表达式为($a++)或者(++$a)并且从第三个表达式开始都有的结果都有规律可寻,也就是说只会影响到(++$a)+表达式2的结果。假设前n个表达式的和为Sn,运算完后$a=5;
则Sn+($a++)=Sn+5;
Sn+(++$a)=Sn+6也就是符合把($a++) 当作 function returnFirst(&$a){ $return=$a; $a=$a+1; return $return ; } 把(++$a)当作 function plusFirst(&$a){ $a=$a+1; return $a;}正确推算出来
是不是php设计在这个问题上的设计缺陷哦。要是的话就很high哦,平生第一碰到这个级别的问题啊。
nnd这个问题太折磨人了当$b=&$a,好像只有在(++$a)在运算表达式的最左边才会出意外的状况。
即:
(++$a)+表达式2+表达式3......
注:表达式为($a++)或者(++$a)并且从第三个表达式开始都有的结果都有规律可寻,也就是说只会影响到(++$a)+表达式2的结果。假设前n个表达式的和为Sn,运算完后$a=5;
则Sn+($a++)=Sn+5;
Sn+(++$a)=Sn+6也就是符合把($a++) 当作 function returnFirst(&$a){ $return=$a; $a=$a+1; return $return ; } 把(++$a)当作 function plusFirst(&$a){ $a=$a+1; return $a;}正确推算出来
是不是php设计在这个问题上的设计缺陷哦。要是的话就很high哦,平生第一碰到这个级别的问题啊。你也搞晕了?
nnd这个问题太折磨人了当$b=&$a,好像只有在(++$a)在运算表达式的最左边才会出意外的状况。
即:
(++$a)+表达式2+表达式3......
注:表达式为($a++)或者(++$a)并且从第三个表达式开始都有的结果都有规律可寻,也就是说只会影响到(++$a)+表达式2的结果。假设前n个表达式的和为Sn,运算完后$a=5;
则Sn+($a++)=Sn+5;
Sn+(++$a)=Sn+6也就是符合把($a++) 当作 function returnFirst(&$a){ $return=$a; $a=$a+1; return $return ; } 把(++$a)当作 function plusFirst(&$a){ $a=$a+1; return $a;}正确推算出来
是不是php设计在这个问题上的设计缺陷哦。要是的话就很high哦,平生第一碰到这个级别的问题啊。也就是符合把($a++) 当作 function returnFirst(&$a){ $return=$a; $a=$a+1; return $return ; } 把(++$a)当作 function plusFirst(&$a){ $a=$a+1; return $a;}正确推算出来
这句话,说了等于没说。。你返回了半天,还是运算过后的$a的值,
nnd这个问题太折磨人了当$b=&$a,好像只有在(++$a)在运算表达式的最左边才会出意外的状况。
即:
(++$a)+表达式2+表达式3......
注:表达式为($a++)或者(++$a)并且从第三个表达式开始都有的结果都有规律可寻,也就是说只会影响到(++$a)+表达式2的结果。假设前n个表达式的和为Sn,运算完后$a=5;
则Sn+($a++)=Sn+5;
Sn+(++$a)=Sn+6也就是符合把($a++) 当作 function returnFirst(&$a){ $return=$a; $a=$a+1; return $return ; } 把(++$a)当作 function plusFirst(&$a){ $a=$a+1; return $a;}正确推算出来
是不是php设计在这个问题上的设计缺陷哦。要是的话就很high哦,平生第一碰到这个级别的问题啊。也就是符合把($a++) 当作 function returnFirst(&$a){ $return=$a; $a=$a+1; return $return ; } 把(++$a)当作 function plusFirst(&$a){ $a=$a+1; return $a;}正确推算出来
这句话,说了等于没说。。你返回了半天,还是运算过后的$a的值,我的意思是
$a = 1;
$c = $a + ($a++);
var_dump($c);//3
$a = 1;
$c = (++$a)+$a;
var_dump($c);//4
$a = 1;
$c = (++$a)+($a++);
var_dump($c);//4第二种和第三种情况很好理解,就是单纯从左到右,并且符合对"先加后返回"或者"先返回后加"的理解
第一种情况呢,如果是从左边到右边运算的话,好像不符合对"先返回后加"的理解。但是如果是按照从右边到左边的运算顺序的话,就解释的通了。
我估计当运算式出现变量以及自加运算时,php会有个优先顺序,先运算自加的过程。
就好比
($a++)相当于 function returnFirst(&$a){ $return=$a; $a=$a+1; return $return ; }
(++$a)相当于 function plusFirst(&$a){ $a=$a+1; return $a;}所以要是把($a++)替代成returnFirst(&$a),把(++$a)替代成plusFirst(&$a)
以上的三种情况都能解释得通。但是,你列举了第四种情况,有变量引用
$a = 1;
$b = &$a;
$c = (++$a)+($a++);
var_dump($c);//5注:
($a++)或者(++$a) 我称之为子表达式
若干个($a++)或者(++$a)相加 我称之为表达式在有变量引用的时候,你用若干个($a++)和(++$a)相加时
只有当(++$a)在运算表达式的最左边才会出意外的状况(指的是出现与用函数替代不一致的结果),并且意外
只影响到(++$a)+“子表达式2”的结果。
也就是说,如果你已经知道(++$a)+“子表达式2”的结果,你还是可以用函数替代“子表达式2”之后的“子表达式”来推算结果。
综上所述,我认为($a++)可以用 returnFirst($a)来理解,(++$a)可以用 plusFirst($a)来理解。
第四种意外情况,可能是自加和引用同时出现时没有考虑到的php设计缺陷。当然这只是我猜测
用vld工具可以看到php的运算过程
第一步 ++$a 得出的表达式值我们用$1表示。
第二步 $a++ 得出的表达式值我们用$2表示。
第三步 计算 $1 + $2。
这个过程应该是没有异议的。关键是 ++$a 的结果是什么?$a++的结果又是什么?
对于++$a, php用递增后的$a来表示表达式的结果, 也就是$1与$a在php的底层是指向同一个zval的。
而$a++呢, php先把$a复制出一份作为$2, 然后把$a加1, 也就是从此之后 $2与$a 不会再有半毛钱关系。问题的关键就在 第二步的$a++改变了$a的值,而且由于$a是引用类型,此操作将不会在$a的副本上进行,这就会同步修改第一步的表达式值$1(因为$a和$1本来就是同一个东西)。有兴趣的同学可以看下php的源码,在zend_vm_def.h中搜索PRE_INC即可找到 前置++ 的底层实现。 PRE_DEC也就是 前置-- 运算也有同样的问题。
明白了这些你就很容易构造出更多不符合预期结果的表达式大家可以试一试
$a = 2;
$b = &$a;echo ++$a + $a++;
echo ++$a + $a*=2;echo --$a + $a--;
echo --$a - $a--;echo ++$a + $a--;