使用"+"(数组并集运算符)合并两个数组,它是如何工作的?

225

我有一些代码,似乎使用+=将两个数组的数据合并,但它并未包含所有元素。这是如何工作的?

示例:

$test = array('hi');
$test += array('test', 'oh');
var_dump($test);

输出:

array(2) {
  [0]=>
  string(2) "hi"
  [1]=>
  string(2) "oh"
}

在PHP中,当对数组使用+运算符时,它代表什么意思?


6
我注意到你的问题使用了+=,而被接受的答案使用了+。根据我的测试,它们的行为似乎是相同的。 - user151841
7
这份文档总结地相当不错。 - artfulrobot
1
可能是参考-在PHP中这个符号代表什么?的重复问题。 - scrowler
@RobbieAverill - 这是那个参考问题所指的问题。因此,如果有任何问题,那个参考问题就是重复的。 - icc97
3
还有其他人对于像数组连接这样基本的事情必须通过array_merge来完成感到有些恐惧吗?这就好像数组默认是关联数组,而数值数组则是二等公民一样。 - icc97
文档的第一个评论和这些答案一样好。 - icc97
9个回答

310

引用自PHP手册上关于语言运算符的部分

+ 运算符返回将右侧数组附加到左侧数组的结果;对于两个数组中存在的键,元素来自左侧数组,右侧数组中匹配的元素将被忽略。

如果您执行以下操作:

$array1 = ['one',   'two',          'foo' => 'bar'];
$array2 = ['three', 'four', 'five', 'foo' => 'baz']; 

print_r($array1 + $array2);

你将会得到

Array
(
    [0] => one   // preserved from $array1 (left-hand array)
    [1] => two   // preserved from $array1 (left-hand array)
    [foo] => bar // preserved from $array1 (left-hand array)
    [2] => five  // added from $array2 (right-hand array)
)

所以+的逻辑与以下代码段等效:

$union = $array1;

foreach ($array2 as $key => $value) {
    if (false === array_key_exists($key, $union)) {
        $union[$key] = $value;
    }
}

如果您对C级别实现的详细信息感兴趣,请前往


请注意,+array_merge()如何合并数组不同:

print_r(array_merge($array1, $array2));

会给你

Array
(
    [0] => one   // preserved from $array1
    [1] => two   // preserved from $array1
    [foo] => baz // overwritten from $array2
    [2] => three // appended from $array2
    [3] => four  // appended from $array2
    [4] => five  // appended from $array2
)

请参考链接页面获取更多示例。


2
@Pacerier 由 php.net 生产的 PHP 没有正式规范,但 +array_merge 都在底层调用了 zend_hash_merge。这也是预期的,因为在 PHP 中,数组被实现为有序哈希映射。 - bishop
1
@Pacerier,php.net的在线文档是最接近规范的记录,但在我看来,这些文档远未达到真正的规范水平:一、它们是在代码编写后更新的;二、它们没有涵盖所有特殊用法的编写。 - bishop
28
PHP的+array_merge函数的行为是反常且不直观的。它们的使用方式与一个简单的英语理解下“添加”或“合并”数组的操作相反。其他语言/库使用+来连接列表(例如Python中),“merge”函数用于将一个对象的键/值对添加到另一个对象中(例如lodash中)。然而,在PHP中,情况正好相反;array_merge可用于连接类似列表的数组,但+不能。与array_merge不同,+始终执行任何其他语言中所称的“merge”的操作。 - Mark Amery
1
@icc97 他们确实只是HashMaps。请参见https://nikic.github.io/2014/12/22/PHPs-new-hashtable-implementation.html。 - Gordon
2
我尝试过提交错误报告(https://bugs.php.net/bug.php?id=73576),以查看是否可以为“array_merge”创建别名“array_concat”。 - icc97
显示剩余6条评论

23
我发现使用这种方式的最好例子在配置数组中。
$user_vars = array("username"=>"John Doe");
$default_vars = array("username"=>"Unknown", "email"=>"no-reply@domain.com");

$config = $user_vars + $default_vars;
$default_vars是默认值数组,$user_vars数组将覆盖在$default_vars中定义的值。在$user_vars中缺失的值现在是从$default_vars中获取的默认变量。
这将以print_r的形式打印出来:
Array(2){
    "username" => "John Doe",
    "email" => "no-reply@domain.com"
}

我希望这可以帮到你!

6

小心处理数字键,如果它们需要保留或者你不想丢失任何内容。

$a = array(2 => "a2", 4 => "a4", 5 => "a5");
$b = array(1 => "b1", 3 => "b3", 4 => "b4");

联合

print_r($a+$b);
Array
(
    [2] => a2
    [4] => a4
    [5] => a5
    [1] => b1
    [3] => b3
)

合并
print_r(array_merge($a, $b));
Array
(
    [0] => a2
    [1] => a4
    [2] => a5
    [3] => b1
    [4] => b3
    [5] => b4
)

6

这个操作符将两个数组合并为一个(与array_merge相同,但是使用array_merge时重复的键会被覆盖)。

有关数组操作符的文档可以在这里找到。


1
这里提醒初学者注意,如果任何一个数组为null,操作的结果也将是null。有些人可能不在意这一点,认为既然是联合操作,如果其中一个数组为null,则结果将是正确(非null)的数组。但是,只有当其中一个数组为空数组时才成立。 - Sandeepan Nath
所以,作为一种良好的实践,我认为我们应该将输入数组初始化为空数组。你们觉得呢? - Sandeepan Nath

3
+ 运算符的结果跟 array_replace() 函数相同,但是由于运算符参数顺序颠倒,所以返回的数组也可能顺序不同。
接下来举另一个例子:
$array1 = array('one', 'two', 'foo' => 'bar');
$array2 = array('three', 'four', 'five', 'foo' => 'baz'); 

print_r($array1 + $array2);
print_r(array_replace($array2, $array1)); //note reversed argument order

输出:

Array
(
    [0] => one   // preserved from $array1
    [1] => two   // preserved from $array1
    [foo] => bar // preserved from $array1
    [2] => five  // added from $array2
)
Array
(
    [0] => one   // preserved from $array1
    [1] => two   // preserved from $array1
    [2] => five  // added from $array2
    [foo] => bar // preserved from $array1
)

+ 的顺序是否被规格保证?array_replace 呢? - Pacerier

1
  1. 数组加法操作将所有数组视为关联数组。
  2. 在加法过程中,若键名冲突,则保留左侧(之前的)值。

我在下面发布代码以使事情更清晰。

$a + $b = array_plus($a, $b)

function array_plus($a, $b){
    $results = array();
    foreach($a as $k=>$v) if(!isset($results[$k]))$results[$k] = $v;
    foreach($b as $k=>$v) if(!isset($results[$k]))$results[$k] = $v;
    return $results;
}

@Tamlyn的代码运行似乎证明了你的说法“数组加操作将所有数组视为关联数组”是错误的。 - Pacerier
@Pacerier,该键也可以是整数。 - Hitesh

1
https://softonsofa.com/php-array_merge-vs-array_replace-vs-plus-aka-union/

话虽如此,我们可以认为 + 运算符有点多余,因为使用 array_replace 函数也可以实现相同的效果。

但是,在某些情况下,它非常方便:比如说你有一个 $options 数组被传递给一个函数/方法,还有默认值作为后备:

// we could do it like this
function foo(array $options)
{
   $defaults = ['foo' => 'bar'];
   
   $options = array_replace($defaults, $options);
 
   // ...
}
 
// but + here might be way better:
function foo(array $options)
{
   $options += ['foo' => 'bar'];
 
   // ...
}

-4
它将把新数组附加到先前的数组中。

-6
$var1 = "example";
$var2 = "test";
$output = array_merge((array)$var1,(array)$var2);
print_r($output);

数组([0] => 示例 [1] => 测试)


1
这个线程多次提到array_merge()不是一致的。 - doublejosh
@doublejosh,“congruent”是什么意思? - Pacerier
2
它们不是相同的。 - doublejosh

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接