224

I have some code that appears to merge the data from two arrays using +=, but it doesn't include all of the elements in the element. How does it work?

Example:

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

Output:

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

What does + mean when used on arrays in PHP?

mickmackusa
  • 43,625
  • 12
  • 83
  • 136
user198729
  • 61,774
  • 108
  • 250
  • 348
  • 6
    I notice your question had `+=` and the accepted answer had `+`. From my testing they seem to behave the same. – user151841 Aug 24 '12 at 17:24
  • 7
    The [documentation](http://php.net/manual/en/language.operators.array.php) sums it up pretty well – artfulrobot Aug 22 '13 at 13:53
  • 1
    possible duplicate of [Reference - What does this symbol mean in PHP?](http://stackoverflow.com/questions/3737139/reference-what-does-this-symbol-mean-in-php) – scrowler Jun 26 '14 at 03:40
  • @RobbieAverill - this is the question that that Reference question refers to. So if anything that Reference question is the duplicate – icc97 Nov 21 '16 at 12:29
  • 3
    Is anyone else slightly horrified that such a fundamental thing as array concatenation has to be done through `array_merge`? It's as if arrays are by default associative arrays and numeric arrays are second class citizens. – icc97 Nov 21 '16 at 12:35
  • (First comment of the documentation)[http://php.net/manual/en/language.operators.array.php#86379] is as good as any of these answers. – icc97 Nov 21 '16 at 12:53

9 Answers9

310

Quoting from the PHP Manual on Language Operators

The + operator returns the right-hand array appended to the left-hand array; for keys that exist in both arrays, the elements from the left-hand array will be used, and the matching elements from the right-hand array will be ignored.

So if you do

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

print_r($array1 + $array2);

You will get

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)
)

So the logic of + is equivalent to the following snippet:

$union = $array1;

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

If you are interested in the details of the C-level implementation head to


Note, that + is different from how array_merge() would combine the arrays:

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

would give you

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
)

See linked pages for more examples.

simhumileco
  • 31,877
  • 16
  • 137
  • 115
Gordon
  • 312,688
  • 75
  • 539
  • 559
  • Is the order of keys after `+` operation guaranteed by the **specs**? – Pacerier Mar 30 '15 at 12:48
  • 2
    @Pacerier PHP produced by php.net doesn't have a formal spec, but both the `+` and `array_merge` call `zend_hash_merge` under the hood. This is also expected, since in PHP arrays are implemented as ordered hash maps. – bishop May 19 '15 at 18:34
  • 1
    @Pacerier The php.net online docs are the closest record to a specification, but IMO those docs fall way short of a true spec: one, they're updated after the code is written; two, they're not written to cover every special usage. – bishop May 25 '15 at 00:44
  • @bishop, It has been over 20 years, Has no one stepped forward with a proposal of a real specs then? – Pacerier May 26 '15 at 03:15
  • @Pacerier To clarify Gordon's link, that specification is for HHVM. While HHVM "deliberately recreates PHP.net bugs and oddities", it should be not be considered a formal specification for PHP as published by PHP.net. – bishop May 26 '15 at 13:28
  • @Pacerier Stas has completed a working draft spec for [PHP 5.6](https://github.com/php/php-langspec/blob/PHP-5.6/spec/00-specification-for-php.md), however it doesn't appear to address this question. I'll raise it for clarification. – bishop Jun 30 '15 at 19:55
  • @bishop, The question is whether Zend will surrender PHP to Facebook. Facebook could simply purchase `php.net` from Zend. Also, by "Stas" you are talking about "Stas Malyshev"? – Pacerier Jul 02 '15 at 07:53
  • 27
    The behaviour of PHP's `+` and `array_merge` is perverse and unintuitive. They're the opposite way round from what a plain-English reading would intuitively tell you 'adding' or 'merging' arrays would do. Other languages/libraries use `+` to concatenate lists (e.g. in Python) and "merge" functions to add the key/value pairs from one object onto another (e.g. in lodash). Yet in PHP it's the other way round; `array_merge` can be used for concatenating list-like arrays but `+` cannot. Unlike `array_merge`, `+` always performs the operation that would be called a "merge" in any other language. – Mark Amery Aug 11 '15 at 11:18
  • @MarkAmery definitely agree, it seems like numeric arrays are second class citizens to associative arrays, or possibly they just are associative arrays with numeric keys under the hood. I think there could just be a `array_concat` method as an alias for `array_merge`. This would be consistent with Python as [dict concatenation is treated the same as merging them](http://stackoverflow.com/questions/1781571/how-to-concatenate-two-dictionaries-to-create-a-new-one-in-python#1784128). – icc97 Nov 21 '16 at 13:19
  • 1
    @icc97 they are indeed only HashMaps. See https://nikic.github.io/2014/12/22/PHPs-new-hashtable-implementation.html – Gordon Nov 21 '16 at 13:33
  • 2
    I've tried [submitting a bug](https://bugs.php.net/bug.php?id=73576) to see if an alias `array_concat` could be created for `array_merge`. – icc97 Nov 21 '16 at 22:04
23

The best example I found for using this is in a config array.

$user_vars = array("username"=>"John Doe");
$default_vars = array("username"=>"Unknown", "email"=>"no-reply@domain.com");

$config = $user_vars + $default_vars;

The $default_vars, as it suggests, is the array for default values. The $user_vars array will overwrite the values defined in $default_vars. Any missing values in $user_vars are now the defaults vars from $default_vars.

This would print_r as:

Array(2){
    "username" => "John Doe",
    "email" => "no-reply@domain.com"
}

I hope this helps!

James
  • 5,137
  • 5
  • 40
  • 80
Frank de Jonge
  • 1,607
  • 1
  • 15
  • 23
6

This operator takes the union of two arrays (same as array_merge, except that with array_merge duplicate keys are overwritten).

The documentation for array operators is found here.

Peter Smit
  • 27,696
  • 33
  • 111
  • 170
  • 1
    A word of caution for beginners here, the result of the operation is **null** if any one of the arrays is **null**. Some might not care about this assuming since it is a union operation, the result will be the proper (not-null) array if one of them is null. But, that holds true if one of the arrays is an **empty** array. – Sandeepan Nath Jul 13 '12 at 06:52
  • So, as a good practice, I think, we should initialize the input arrays as empty arrays. What do you guys say? – Sandeepan Nath Jul 13 '12 at 06:58
5

Carefull with numeric keys, if they should be preserved or if you don't want to loose anything

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

union

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

merge

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

The + operator produces the same results as array_replace(). However since the operator arguments are reversed, the ordering of the resulting array may also be different.

Expanding on another example from this page:

$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

outputs:

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
)
Tamlyn
  • 22,122
  • 12
  • 111
  • 127
1
  1. Array plus operation treats all array as assoc array.
  2. When key conflict during plus, left(previous) value will be kept

I post the code below to make things clear.

$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;
}
Gucci Koo
  • 541
  • 4
  • 10
1

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

That being said, we could think of the + operator as kinda redundant, since the same can be achieved with array_replace function.

However, there are cases, where it comes in handy: say you have an $options array being passed to a function/method, and there are also defaults to be used as fallback:

// 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'];
 
   // ...
}
n0099
  • 520
  • 1
  • 4
  • 12
-4

It will append the new array to the previous.

SorcyCat
  • 1,206
  • 10
  • 19
-6
$var1 = "example";
$var2 = "test";
$output = array_merge((array)$var1,(array)$var2);
print_r($output);

Array ( [0] => example [1] => test )

Henning
  • 5
  • 1