zoco

PHP是世界上最好的语言!之array_merge

2015-03-02


最近在使用函数 array_merge 合并两个数组时,得到的结果总是不确定,代码如这样:

$arrResult = array_merge($arrInput1, $arrInput2);

如果已踩过这个坑,肯定能一眼看出代码的潜在问题,以及如何避免,但是问题究竟是什么呢?变量 $arrResult 的值会根据函数 array_merge 的两个参数的类型及值而变化,如:键为数字的字典、null 等,详细问题解释说明请继续往下看!

来自 PHP 官方网站的array_merge函数说明

函数功能:合并一个或多个数组

函数原型:

array array_merge(array $array1[, array $...])

函数 array_merge 将一个或多个数组的单元合并,后一个数组中的值追加到前一个数组的后面,并作为函数结果返回。

示例场景1:如果输入数组中有相同的字符串键名,则该键名后面的值将覆盖前一个值,如:
<?php
// PHP 5.6.15
$a = array('hello' => 1, 'world' => 2);
$b = array('hi' => 1, 'world' => 3);

$c = array_merge($a, $b);
var_dump($c);

$d = array_merge($b, $a);
var_dump($d);

执行脚本后的结果为:

array(3) {
  ["hello"]=>
  int(1)
  ["world"]=>
  int(3)
  ["hi"]=>
  int(1)
}
array(3) {
  ["hi"]=>
  int(1)
  ["world"]=>
  int(2)
  ["hello"]=>
  int(1)
}
示例场景2:如果输入数组只有一个且为数字索引,即其中一个数组为 array(),则键名会以连续方式重新索引,如:
<?php
 $a = array(3 => 3, 2=>2, 5=>5);

 $b = array_merge($a);
 var_dump($b);

 $c = array_merge($a, array());
 var_dump($c);

 $d = array_merge(array(), $a);
 var_dump($d);

执行脚本后的结果为:

array(3) {
  [0] =>
  int(3)
  [1] =>
  int(2)
  [2] =>
  int(5)
}
array(3) {
  [0] =>
  int(3)
  [1] =>
  int(2)
  [2] =>
  int(5)
}
array(3) {
  [0] =>
  int(3)
  [1] =>
  int(2)
  [2] =>
  int(5)
}
示例场景3:如果输入数组为标准的数组,即索引为默认的数字索引,则后面的值不会覆盖原来的值,而是追加到后面,如:
<?php
// PHP 5.6.15
$a = array('hello', 20, 'world');
$b = array(5, 'hello', 20);

$c = array_merge($a, $b);
var_dump($c);

$d = array_merge($b, $a);
var_dump($d);

执行脚本后的输出为:

array(6) {
  [0]=>
  string(5) "hello"
  [1]=>
  int(20)
  [2]=>
  string(5) "world"
  [3]=>
  int(5)
  [4]=>
  string(5) "hello"
  [5]=>
  int(20)
}
array(6) {
  [0]=>
  int(5)
  [1]=>
  string(5) "hello"
  [2]=>
  int(20)
  [3]=>
  string(5) "hello"
  [4]=>
  int(20)
  [5]=>
  string(5) "world"
}

又如:

<?php
// PHP 5.6.15
$a = array(10 => 1, 'world' => 2);
$b = array('hi' => 1, 10 => 3);

$c = array_merge($a, $b);
var_dump($c);

$d = array_merge($b, $a);
var_dump($d);

执行脚本后的输出为:

array(4) {
  [0]=>
  int(1)
  ["world"]=>
  int(2)
  ["hi"]=>
  int(1)
  [1]=>
  int(3)
}
array(4) {
  ["hi"]=>
  int(1)
  [0]=>
  int(3)
  [1]=>
  int(1)
  ["world"]=>
  int(2)
}

对于包含有数字索引的数组的合并结果是不是和预想的有些不一样呢?对于不注意的同学来说,接下来会犯这样的错误的:

合并完两个 array 后,会使用以前的 key 去进行操作

坑的结论:

当合并数组中有数字键名时,其会被重新编号!

但是,如果想完全保留原有数组并只想新的数组附加到后面,则需要使用 + 运算符。

但是,问题又来了。

如果$arr不是数组,就会发生难以意料的隐患。

所以个人认为在此场景下最后最好的做法:

<?php
// PHP 5.6.15
$a = array(10 => 1, 'world' => 2);
$b = array('hi' => 1, 10 => 3);
settype($a, 'array');
settype($b, 'array');

$c = $a + $b;
var_dump($c);

$d = $b + $a;
var_dump($d);

执行脚本后的输出为:

array(3) {
  [10] =>
  int(1)
  'world' =>
  int(2)
  'hi' =>
  int(1)
}
array(3) {
  'hi' =>
  int(1)
  [10] =>
  int(3)
  'world' =>
  int(2)
}