β

神奇的array_merge

三分's blog 101 阅读
php
在看Twig模板代码的时候发现这种用法
$defaultConfig = array("aa"=>1, "bb"=>2);
$userConfig = array("aa"=>33, "cc"=>3);
$config = array_merge($defaultConfig, $userConfig);
把$defaultConfig 赋值成默认值,后面的$userConfig 修改了之后直接调用array_merge,如果后面有相同的key,就会直接覆盖掉原来的默认值。
array_merge()函数用过很多次,都是当成普通合并数组来用,还没想到过有这功能,就去看了一下手册:
array_merge() 将一个或多个数组的单元合并起来,一个数组中的值附加在前一个数组的后面。返回作为结果的数组。
如果输入的数组中有相同的字符串键名,则该键名后面的值将覆盖前一个值。然而,如果数组包含数字键名,后面的值将不会覆盖原来的值,而是附加到后面。
如果只给了一个数组并且该数组是数字索引的,则键名会以连续方式重新索引。
说明这种用法是很合理正当的,但是我总觉得说不出的奇怪,同时也想起来以前做项目时出现的一个bug:
表现就是有几个用户的装备突然丢了,根据log发现用户的确是拥有过这个装备,而且没有log记录下来曾经消耗或出售过。一步步排查,发现出现bug的代码是已经运行了两年都没出过问题的!array_merge就是凶手之一。
因为装备id是通过uniqid()生成的,大家都习惯了在数组中用id做key,装备对象做value。出现bug的代码是在某个地方用了array_merge(),而uniqid()函数没有加前缀参数,uniqid有可能生成纯数字的id,而array_merge()在合并时把纯数字id重新索引!结果就是下面这个例子
$array3 = array("1"=>3, "cd"=>43);
$array4 = array("34030"=>4, "cdf"=>234);
 
$arr5 = array_merge($array3, $array4);
var_dump($arr5);
结果是
array(4) { [0]=> int(3) ["cd"]=> int(43) [1]=> int(4) ["cdf"]=> int(234) }
$array3中的1变成了$arr5中的0,$array4中的34030变成了$arr5中的1。
而在当时项目中,这个值是我们的装备id!所以它就这样消失了。
结论很简单:1. 使用uniqid的时候尽量加上prefix参数; 2. 熟悉array_merge的这两个奇葩“特性”——后面的覆盖前面的 和 数字key会被重新索引。
再回到Twig模板中的这种用法,的确简单讨巧,但是在项目中我不提倡这么做。至少在这么做之前你得清楚自己在做什么。
php
作者:三分's blog
勇敢的少年啊,快去创造奇迹!
原文地址:神奇的array_merge, 感谢原作者分享。