要说起编程技巧,很多软件工程师可是犹如滔滔江水,连绵不绝,又犹如黄河泛滥,一发不可收拾。但我要是说编程里也有潜规则,你是不是会有很多问号?就算是很多资深老程序员编程时也未必能熟记,往往因轻车熟路而翻车,生产低级BUG。
小马从事PHP编程多年,也见过不少老程序员,我们俗称老司机,要是诸如什么时候应该用策略模式,什么时候用代理模式比较好,应不应该写IOC,Yii框架好还是Laravel框架好等等的话题,谈起来那简直可以眉飞色舞,唾沫横飞不在话下。但你要是细细盘查代码,有时候还真是能发现不少因想当然而产生的BUG隐患。
今天小马整理了一下PHP编程中必须要知道的5个潜规则,要拿起小本本记起来哦,违反这些规则很可能会给软件系统埋下致命的隐患。
潜规则1:empty() 函数检查空对象会返回false
逻辑实现中我们往往会对取值的结果集进行判断是否为空,自然第一印象就是敲出empty()函数来判断,看起来似乎水到渠成,但是这往往是一个缺陷隐患的开始。
假如我们遇到的结果集返回的正式一个对象集合,如果是空对象,那么这个时候对不起了,empty()函数将返回false,也就是它将认为这个变量结果不是空的。以至于后面的上下文逻辑很可能因为此处判断错误的原因,导致更严重的业务逻辑错误或者程序异常,这个潜规则很容易违反,尤其是拥有多年经验的老手也难以完全幸免。
我们来剖开现象看本质,看看empty函数是如何悄悄把你放倒的。代码如图。
empty判断空对象返回false(是的,不用怀疑水印,正是本人,已从百家弃坑~~)
# 潜规则2:json_encode()函数只支持utf-8编码
关于这点,其实PHP官方文档已经说得很明白了:
待编码的value,除了resource类型之外,可以为任何数据类型。所有字符串数据的编码必须是 UTF-8。
但是违反这个规则的工程师却不在少数。原因在于当前编码规范虽然默认都公认为utf-8,但有些比较老的系统,因为历史原因,DB字符集仍然还在大量使用着GBK的编码规范,这点鹅厂也不例外。这就导致很多人疏忽编码规范,直接将GBK编码的字符串进行json_encode,自然是不允许的,返回乱码。说到这里,其兄弟函数json_decode也是一样的。所以可以调用之前可以使用 iconv或mb_convert_encoding先进行编码转换。
# 潜规则3:字符串编码判断函数mb_detect_encoding的误判
这个规则小马曾经也违反过,可谓深受其害。这事还得从那次实现一个实名认证API说起。第三方的认证接口要求姓名传参必须是utf-8编码,但是由于前端可能会存在各种未知的代码,所以必须先进行字符串编码的判断,然后使用转码函数都转成utf-8规范。
逻辑是这么写的:$encode = mb_detect_encoding($name, array('ASCII','UTF-8','GB2312', 'GBK', 'BIG5'));$name = mb_convert_encoding($name, 'UTF-8', $encode);
这段代码的作用是检测字符串的编码,然后将该编码转换为utf-8,咋一看,这肯定是没啥问题是吧。但是“奇迹”就这样发生了。小马得到了一个非必现的BUG反馈,有些用户姓名编码格式不正确,注意是有些用户。
小马排查发现,据说是当name字符串较短时,检测结果产生偏差的可能性很大。什么意思呢?假设“李南”这个字符串原本为GBK,但是被mb_detect_encoding误判为UTF-8编码,然后mb_convert_encoding函数不对其进行utf-8编码转化。这样自然最终得到的name并不是utf-8了。
如何解决呢?我们看下mb_convert_encoding参数说明:“前两参数分别是:被检测的输入变量、编码方式的检测顺序(一旦为真,后面自动忽略)。”,可以对编码检测的顺序进行调整,将最大可能性放在前面,这样减少被错误转换的机会。一般要先排gb2312,当有GBK和UTF-8时,需要将常用的排列到前面。调整之后的代码:$encode = mb_detect_encoding($name, array('ASCII','GB2312', 'GBK', 'BIG5','UTF-8'));
这个细节是不是很惊喜?
# 潜规则4:浮点运算将精度丢失
说这个之前,我们来看下一段代码:$float = 0.58;echo intval($float * 100);
大多数人会认为这个没啥,返回58呗。这其实就是它的潜在隐患。实践证明,其返回结果是57。再比如(8 - 6.4) == 1.6)的结果是false。这个浮点数精确问题存在于编程语言,原因是因为有穷的小数,在计算机的二进制表示里却是无穷的,浮点运算时应注意丢失精度(PHP遵循IEEE 754双精度)。这一点非常重要,违反这个潜在规则将导致业务计算结果的偏差,比较危险。
# 潜规则5:foreach地址引用要注意释放
这点也是比较危险的,虽然地址引用用起来非常丝滑,但小马还是不建议使用地址引用,这点仁者见仁智者见智吧。还是先看一段代码:
在foreach中使用地址引用
这段代码在foreach中使用了地址引用,然后在进行一次foreach。这个时候问题来了,看下输出结果:
在foreach中使用地址引用运行结果
很明显这个结第二个数组的第三个值变为2而不是原来的3。大家想想如何这个场景用在购物车物品的循环或者金额等的计算,这不是导致直接数值计算不准确,仍然是一个危险系数极高的潜在规则。
又到了真相只有一个的环节了,我们对引用地址变量进行释放后再看看结果:
对地址引用进行释放
注意第7行的代码,结果自然是OK了。
对地址引用进行释放运行结果
好了,关于PHP编程的潜规则就先说到这了,这些都是比较容易被忽视且尤其致命的潜在规则,也希望对大家能有所帮助。谢谢品阅。
彩蛋时间:
注意到什么了呢?