资讯专栏INFORMATION COLUMN

PHP 一个诡异的加法算法的研究

gekylin / 3396人阅读

摘要:然而实际上,这个结果反而是正确的。结论我认为出现这种诡异的结果应该算是的,同时,这也说明了此种问题不太容易被发现和暴露,这要求我们平常写代码的时候尽量使用常用的语法,和精干的语句,让代码和逻辑达到最佳的平衡点。

前言

之前我在面试的时候,遇到许多年轻人都声称自己精通php,有过许多项目经验等等。然而,当真正笔试的时候,我问到

$result=1;
if(-1){
 $result=2;
}
echo $result;

中,$result最终结果的时候,许多人信誓旦旦的告诉我是1。 试想,这样一个连基本算法都搞不清楚的人,即使有过再多的项目经验,你敢用吗?

引申

对于算法的一些问题,我个人一向是非常较真的,我招人的时候也是非常侧重此方面,因此我对php的关注也是在这方面多些。故事得从一个知乎上的问题开始。

//第一题
//第二题

这个问题非常的有意思,也是一个大坑,许多人都算错了,包括很多我认识的大牛。在这里就不点名字,以免其羞愧。 然而你以为我一开始算对了吗?我算对了第一题,第二题却是百思不得其解。最后用调试工具一番调试才算理清头绪。索性发出来与大家一起分享这个有意思的问题。

分析 第一题 php语言解释

这个其实非常简单,++a这种单目运算符的运算结果还是自身。 所以

$a=1;
$b=&$a;
echo (++$a)+(++$a);
//换种写法就等同于
$a=1;
$a=++$a; //2
$a=++$a; //3
$a=$a+$a;//3+3=6

哈,很多人肯定以为是等于5,然而这个是操作的同一个变量,等同于改变了两次$a的值,最后相加的时候,自然就是改变后的值相加,所以等于6。

正常情况

然而在php中,为了照顾人类的逻辑,默认情况下,即使名字相同的基本类型的变量,也不会使用同一个变量地址,因此,以上代码会被解析为

$a=1;
echo (++$a)+(++$a);
//换种写法就等同于
$a=1;
$a=++$a; //2
$b=++$a; //3
$a=$a+$b;//2+3=5

但是由于

$b=&$a;

的存在,使得下面的第一个$a的计算方式变成了传统的c语言计算方式,所以输出了_看起来错误的结果_。
然而实际上,这个结果反而是正确的。PHP中的糖语法宠坏了那些基础本来不扎实的孩子,对这种加法做了特别的运算处理而已。

深入思考

为什么说等于6才是正确结果呢?我们知道现行高级语言大多来自c语言,php也不例外,我们这里用c语言来写一遍上述代码,然后通过反汇编来看看机器到底是怎么执行的。

其实无论是否注释下面的取地址,结果都是6。 我们看汇编代码

这里更清晰的看到a的值的变化。 即是

mov edx,dword ptr [a] ;a的值为3
add edx,dword ptr [a] ; 3+3
问题二 问题发现

由问题一的结论来分析问题二,反而陷入了一个更大的舞曲,为什么呢?

echo (++$a)+(++$a)+(++$a);  //10
/*
按照问题一的分析,此处的结果应为
a=1+1  //2
a=a+1  //3
a=a+1  //4
a=a+a+a //12
*/

然而输出的结果却是10.

动手实验

这里我们用一个工具phpdebug.exe来调试下看看。

可以看到的a的值的变化:

1->2->3->4

然后我们再来调试一下注释掉

$b=&$a;

的结果。

这里在第二步的时候重新给了变量$a一个地址,实际上同是叫$a,其实他们已经不是同一个变量了。 所以他输出的结果为9。

实验结果

但是为什么上面的结果为10呢? 这其实是因为

$b=&$a;

这个取地址运算只起效了一句运算指令,就是只管事了第一回合,对于以后的运算,php还是用了平常的算法。 即:

$a=1;
$b=&$a;
echo (++$a)+(++$a)+(++$a);
/*
这段实际上是
$a=++$a; //2
$a=++$a; //3
//注意了,前两个已经得到结果了,第三个我们用一个新的变量$c。
$c=++$a; //4
$a=$a+$a; //3+3=6
$a=$a+$c; //6+4=10
*/
结论

我认为出现这种诡异的结果应该算是php的bug,同时,这也说明了此种问题不太容易被发现和暴露,这要求我们平常写代码的时候尽量使用常用的语法,和精干的语句,让代码和逻辑达到最佳的平衡点。 此BUG我已经反馈到php官方。

后续

最新的php7中已经修复了此bug。

修订记录

初稿 2015-09-11

修订 2016-05-27

修订 2016-05-30

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/21741.html

相关文章

  • 程序员算法趣题Q54: 偷懒算盘

    摘要:且听下回分解基于动态规划策略的优化解法参见程序员的算法趣题偷懒的算盘上一篇程序员的算法趣题同数包夹程序员的算法趣题同数包夹本系列总目录参见程序员的算法趣题详细分析和全解程序员的算法趣题详细分析和全解 目录 1. 问题描述 2. 解题分析 3. 代码及测试 4. 后记 1. 问题描述   ...

    wangzy2019 评论0 收藏0
  • Laravel核心解读--完结篇

    摘要:过去一年时间写了多篇文章来探讨了我认为的框架最核心部分的设计思路代码实现。为了大家阅读方便,我把这些源码学习的文章汇总到这里。数据库算法和数据结构这些都是编程的内功,只有内功深厚了才能解决遇到的复杂问题。 过去一年时间写了20多篇文章来探讨了我认为的Larave框架最核心部分的设计思路、代码实现。通过更新文章自己在软件设计、文字表达方面都有所提高,在刚开始决定写Laravel源码分析地...

    laoLiueizo 评论0 收藏0
  • PHP 5.6新特性之一:内部操作符重载

    摘要:转载自我的博客在众多的新特性中,我觉得这是最神奇甚至是诡异的一个,如果有不理解这个概念的朋友,可能连它的说明都看不懂。在这个例子中操作符被重载为,操作符被重载为。再重载成操作符,以后咋跟踪代码。。。 转载自我的博客:http://70.io/2014/03/php-5_6-internal-operator-overloading 在众多php 5.6的新特性中,我觉得这是最...

    canopus4u 评论0 收藏0
  • PHP引用,你知道多少?

    摘要:最近面试他人的过程中,问了一些关于引用的知识,发现很多同学对这方面知之甚少,还有很多工作中基本没有使用过。没钱给大家发红包,给大家推荐一家上海的好公司。对于上海的小伙伴或者想去上海的小伙伴,强烈建议去看看。 真的是变懒了,一个月一篇的节凑都很难保证了。 最近面试他人的过程中,问了一些关于PHP引用的知识,发现很多同学对这方面知之甚少,还有很多工作中基本没有使用过。甚至有人告诉我要少用引...

    williamwen1986 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<