首页 >后端开发 >php教程 >你会加法吗?我真是纠结了!求助,求解释

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

WBOY
WBOY原创
2016-06-23 14:20:471263浏览

$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

求解释。


回复讨论(解决方案)


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

$a = 1;
$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;

其他类同

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

求解释第三和第一的区别  既然是后自加 为甚么第一个不是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 式的区别

xu大我还是不太理解和1式的区别  如果按照3式的分析,得到结果是2,当然这肯定是不对的  1式和3式的核心区别在哪里呢?....

$c =  $a + ($a++);
是以变量参与运算的

xu大我还是不太理解和1式的区别  如果按照3式的分析,得到结果是2,当然这肯定是不对的  1式和3式的核心区别在哪里呢?....

++$a   
表示$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;      输出是1

echo ++$a;  //  先给$a做加1运算,再返回$a    相当于   $a=$a+1;  echo $a;  输出是2

xu大我还是不太理解和1式的区别  如果按照3式的分析,得到结果是2,当然这肯定是不对的  1式和3式的核心区别在哪里呢?.... 你也晕乎了是吧,哈哈哈

对于
$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的是如何理解呢?

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
第一个好像就解释错了。

又无括号多没有关系,你这都是加法运算,由加法的结合律可知,无论是否有括号,括号加在哪里,都不会影响最终的结果

$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;$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的那个怎么解释。

对于
$a = 1;
$b = &$a;
var_dump($c);//5
由于应用的存在,情况要复杂点

由于有一个对 $b 的赋值过程,这相当于
$a = 1;
$c = (++$a)+($b = $a+1);
var_dump($c);//5

对于
$a = 1;
$b = &$a;
var_dump($c);//5
由于应用的存在,情况要复杂点

由于有一个对 $b 的赋值过程,这相当于
$a = 1;
$c = (++$a)+($b = $a+1);
var_dump($c);//5 不明白。还是有点晕。

反正执行过程中 $a++不影响$a的值,而是执行完毕才改变,类似for $i=...循环,$i在退出循环后值还要+1
++$a则是在执行过程中就改变了$a的值,执行后则不变

$b=&$a 导致了$a++做了“执行后”这个动作,所以$a++也递增了

我习惯就是这样理解的,也不知是否合适

$c =  $a + ($a++);
是以变量参与运算的


xu大我还是不太理解和1式的区别  如果按照3式的分析,得到结果是2,当然这肯定是不对的  1式和3式的核心区别在哪里呢?....

$a=1;
$c= $a+($a++);
红色的$a是以变量参与运算,但是为什么是2呢? 难道$a+($a++)先运行($a++)部分吗?  
测试过去掉$a++的括号结果还是一样,那么跟括号没有关系。那么表达式不是从左往右计算吗?

$c =  $a + ($a++);
是以变量参与运算的


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


对于
$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


对于
$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 更晕了,听了你的一席话,我又觉得斑竹的解释有问题了。。。

对于
$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哦,平生第一碰到这个级别的问题啊。


对于
$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哦,平生第一碰到这个级别的问题啊。 你也搞晕了?


对于
$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哦,平生第一碰到这个级别的问题啊。

也就是符合把($a++) 当作 function returnFirst(&$a){ $return=$a; $a=$a+1; return $return ; }  把(++$a)当作 function plusFirst(&$a){ $a=$a+1; return $a;}正确推算出来
这句话,说了等于没说。。你返回了半天,还是运算过后的$a的值,



对于
$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哦,平生第一碰到这个级别的问题啊。

也就是符合把($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设计缺陷。当然这只是我猜测

C/C++和php的前加加后加加结果还不一样,php是通过zend内核来操作变量在内存中的分配,相比来说c/c++的还更好理解。

C/C++和php的前加加后加加结果还不一样,php是通过zend内核来操作变量在内存中的分配,相比来说c/c++的还更好理解。 请帮忙我们捋一捋吧。。。好理解的话。

看了楼上的各种解释,心里不免有很多疑问,总觉得每一种解释都很牵强。我觉得应该把它看作是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--;

声明:
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn