你会加法吗?我真是纠结了!求助,求解释

梦康 2013-08-29 03:21:49
$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

求解释。
...全文
615 28 打赏 收藏 转发到动态 举报
写回复
用AI写文章
28 条回复
切换为时间正序
请发表友善的回复…
发表回复
hengyu654 2013-08-31
  • 打赏
  • 举报
回复
看了楼上的各种解释,心里不免有很多疑问,总觉得每一种解释都很牵强。我觉得应该把它看作是php的一个bug,而不是一个特性。 用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--;
Hx_Moon_ 2013-08-30
  • 打赏
  • 举报
回复
C/C++和php的前加加后加加结果还不一样,php是通过zend内核来操作变量在内存中的分配,相比来说c/c++的还更好理解。
lei1314lei 2013-08-30
  • 打赏
  • 举报
回复
引用 24 楼 zhoumengkang 的回复:
[quote=引用 21 楼 lei1314lei 的回复:] [quote=引用 14 楼 xuzuning 的回复:] 对于 $a = 1; $b = &$a; var_dump($c);//5 由于应用的存在,情况要复杂点 由于有一个对 $b 的赋值过程,这相当于 $a = 1; $c = (++$a)+($b = $a+1); var_dump($c);//5
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哦,平生第一碰到这个级别的问题啊。[/quote] 也就是符合把($a++) 当作 function returnFirst(&$a){ $return=$a; $a=$a+1; return $return ; } 把(++$a)当作 function plusFirst(&$a){ $a=$a+1; return $a;}正确推算出来 这句话,说了等于没说。。你返回了半天,还是运算过后的$a的值,[/quote] 我的意思是 $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设计缺陷。当然这只是我猜测
梦康 2013-08-30
  • 打赏
  • 举报
回复
引用 21 楼 lei1314lei 的回复:
[quote=引用 14 楼 xuzuning 的回复:] 对于 $a = 1; $b = &$a; var_dump($c);//5 由于应用的存在,情况要复杂点 由于有一个对 $b 的赋值过程,这相当于 $a = 1; $c = (++$a)+($b = $a+1); var_dump($c);//5
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哦,平生第一碰到这个级别的问题啊。[/quote] 也就是符合把($a++) 当作 function returnFirst(&$a){ $return=$a; $a=$a+1; return $return ; } 把(++$a)当作 function plusFirst(&$a){ $a=$a+1; return $a;}正确推算出来 这句话,说了等于没说。。你返回了半天,还是运算过后的$a的值,
梦康 2013-08-30
  • 打赏
  • 举报
回复
引用 21 楼 lei1314lei 的回复:
[quote=引用 14 楼 xuzuning 的回复:] 对于 $a = 1; $b = &$a; var_dump($c);//5 由于应用的存在,情况要复杂点 由于有一个对 $b 的赋值过程,这相当于 $a = 1; $c = (++$a)+($b = $a+1); var_dump($c);//5
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哦,平生第一碰到这个级别的问题啊。[/quote]你也搞晕了?
blizzf99 2013-08-30
  • 打赏
  • 举报
回复
顶帖收藏~~~~
lei1314lei 2013-08-30
  • 打赏
  • 举报
回复
引用 14 楼 xuzuning 的回复:
对于 $a = 1; $b = &$a; var_dump($c);//5 由于应用的存在,情况要复杂点 由于有一个对 $b 的赋值过程,这相当于 $a = 1; $c = (++$a)+($b = $a+1); var_dump($c);//5
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哦,平生第一碰到这个级别的问题啊。
梦康 2013-08-30
  • 打赏
  • 举报
回复
引用 26 楼 linux_PHP_ 的回复:
C/C++和php的前加加后加加结果还不一样,php是通过zend内核来操作变量在内存中的分配,相比来说c/c++的还更好理解。
请帮忙我们捋一捋吧。。。好理解的话。
梦康 2013-08-29
  • 打赏
  • 举报
回复
引用 19 楼 lei1314lei 的回复:
[quote=引用 14 楼 xuzuning 的回复:] 对于 $a = 1; $b = &$a; var_dump($c);//5 由于应用的存在,情况要复杂点 由于有一个对 $b 的赋值过程,这相当于 $a = 1; $c = (++$a)+($b = $a+1); var_dump($c);//5
那如果是 $c=($a++)+($a++) 要理解成 $c=($b=$a+1)+($b=$a+1)吗? $c=($a++)+($a++) 返回的结果是3[/quote]更晕了,听了你的一席话,我又觉得斑竹的解释有问题了。。。
lei1314lei 2013-08-29
  • 打赏
  • 举报
回复
引用 14 楼 xuzuning 的回复:
对于 $a = 1; $b = &$a; var_dump($c);//5 由于应用的存在,情况要复杂点 由于有一个对 $b 的赋值过程,这相当于 $a = 1; $c = (++$a)+($b = $a+1); var_dump($c);//5
那如果是 $c=($a++)+($a++) 要理解成 $c=($b=$a+1)+($b=$a+1)吗? $c=($a++)+($a++) 返回的结果是3
lei1314lei 2013-08-29
  • 打赏
  • 举报
回复
引用 7 楼 xuzuning 的回复:
$c = $a + ($a++); 是以变量参与运算的
引用 6 楼 anyilaoliu 的回复:
xu大我还是不太理解和1式的区别 如果按照3式的分析,得到结果是2,当然这肯定是不对的 1式和3式的核心区别在哪里呢?....
估计得这么理解 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
lei1314lei 2013-08-29
  • 打赏
  • 举报
回复
引用 7 楼 xuzuning 的回复:
$c = $a + ($a++); 是以变量参与运算的
引用 6 楼 anyilaoliu 的回复:
xu大我还是不太理解和1式的区别 如果按照3式的分析,得到结果是2,当然这肯定是不对的 1式和3式的核心区别在哪里呢?....
$a=1; $c=$a+($a++); 红色的$a是以变量参与运算,但是为什么是2呢? 难道$a+($a++)先运行($a++)部分吗? 测试过去掉$a++的括号结果还是一样,那么跟括号没有关系。那么表达式不是从左往右计算吗?
ImN1 2013-08-29
  • 打赏
  • 举报
回复
反正执行过程中 $a++不影响$a的值,而是执行完毕才改变,类似for $i=...循环,$i在退出循环后值还要+1 ++$a则是在执行过程中就改变了$a的值,执行后则不变 $b=&$a 导致了$a++做了“执行后”这个动作,所以$a++也递增了 我习惯就是这样理解的,也不知是否合适
梦康 2013-08-29
  • 打赏
  • 举报
回复
引用 14 楼 xuzuning 的回复:
对于 $a = 1; $b = &$a; var_dump($c);//5 由于应用的存在,情况要复杂点 由于有一个对 $b 的赋值过程,这相当于 $a = 1; $c = (++$a)+($b = $a+1); var_dump($c);//5
不明白。还是有点晕。
xuzuning 2013-08-29
  • 打赏
  • 举报
回复
对于 $a = 1; $b = &$a; var_dump($c);//5 由于应用的存在,情况要复杂点 由于有一个对 $b 的赋值过程,这相当于 $a = 1; $c = (++$a)+($b = $a+1); var_dump($c);//5
梦康 2013-08-29
  • 打赏
  • 举报
回复
引用 12 楼 xuzuning 的回复:
又无括号多没有关系,你这都是加法运算,由加法的结合律可知,无论是否有括号,括号加在哪里,都不会影响最终的结果
$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
那请问最后一个引用后变成5的那个怎么解释。
xuzuning 2013-08-29
  • 打赏
  • 举报
回复
又无括号多没有关系,你这都是加法运算,由加法的结合律可知,无论是否有括号,括号加在哪里,都不会影响最终的结果
$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
梦康 2013-08-29
  • 打赏
  • 举报
回复
引用 1 楼 yaotomo 的回复:
1)表达式从左到右执行,所以$a这时还是1,1+2=3 2)同样是从左到右执行,++$a为2,这时$a已经自加过,所以2+2=4 3)++$a是先自加,这时$a值为2,后面的$a++是后自加,所以2+2=4 4)因为是改变引用的值,所以是2+3=5
第一个好像就解释错了。
梦康 2013-08-29
  • 打赏
  • 举报
回复
引用 5 楼 xuzuning 的回复:
对于 $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 式的区别
综合斑竹两次的回答,第一个哈第三的解释,那就是说有括号的时候先运算括号内的,然后都转化为标量了再做计算是吧。 我还有疑惑,最后一个结果是5的是如何理解呢?
梦康 2013-08-29
  • 打赏
  • 举报
回复
引用 6 楼 anyilaoliu 的回复:
xu大我还是不太理解和1式的区别 如果按照3式的分析,得到结果是2,当然这肯定是不对的 1式和3式的核心区别在哪里呢?....
你也晕乎了是吧,哈哈哈
加载更多回复(8)

21,882

社区成员

发帖
与我相关
我的任务
社区描述
从PHP安装配置,PHP入门,PHP基础到PHP应用
社区管理员
  • 基础编程社区
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧