134

When I use array_merge() with associative arrays I get what I want, but when I use them with numerical key arrays the keys get changed.

With + the keys are preserved but it doesn't work with associative arrays.

I don't understand how this works, can anybody explain it to me?

Wesley Murch
  • 101,186
  • 37
  • 194
  • 228
Elly
  • 1,343
  • 2
  • 9
  • 4

2 Answers2

179

Because both arrays are numerically-indexed, only the values in the first array will be used.

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.

http://php.net/manual/en/language.operators.array.php

array_merge() has slightly different behavior:

If the input arrays have the same string keys, then the later value for that key will overwrite the previous one. If, however, the arrays contain numeric keys, the later value will not overwrite the original value, but will be appended. Values in the input array with numeric keys will be renumbered with incrementing keys starting from zero in the result array.

http://php.net/manual/en/function.array-merge.php

Christopher Armstrong
  • 7,907
  • 2
  • 26
  • 28
  • 1
    well array_merge is what I want, but why does it change the numerical index? If I merge `array(1 => 'a', 2 => 'b') ` with `array(20 => 'x')` I get a 0, 1, 2 index, not 1,2,20 :| – Elly Aug 14 '11 at 21:11
  • Because that's how it was written. You may need to write your own function to perform the merge if you need different rules under certain conditions. – Christopher Armstrong Aug 14 '11 at 21:16
  • 5
    hm... so `+` is like array_merge with reverse arguments, and without the numerical key renumbering? that means I only have to reverse my parameters – Elly Aug 14 '11 at 21:26
  • One of the previous developers from some code I'm working on uses + to merge arrays in *every* occasion. It causes a lot of issues and premature hair-loss for others if you don't know exactly what it does. Excellent answer too! – Matt Fletcher Mar 19 '13 at 10:16
  • @MattFletcher, actually without seeing your code, it's hard to say, why he did that. Maybe one of his aims was to avoid renumbering? – Denis V Feb 24 '14 at 15:10
  • 6
    In our code base we stopped using + and array_merge for arrays, instead using two new functions we wrote. "array_merge_by_key" and "array_concat" instead of a single function with a heuristic that tries to guess at what you want – Yuliy Jul 28 '14 at 00:38
  • This can be written much more clearly and succinctly than having to read a mess of prose. "+: the first array's value is used. array_merge: the second array's value is used, unless the key is numeric" – ahnbizcad Jun 26 '19 at 19:18
39

These two operation are totally different.

array plus

  1. Array plus operation treats all array as assoc array.
  2. When key conflict during plus, left(previous) value will be kept
  3. null + array() will raise fatal error

array_merge()

  1. array_merge() works different with index-array and assoc-array.
  2. If both parameters are index-array, array_merge() concat index-array values.
  3. If not, the index-array will to convert to values array, and then convert to assoc array.
  4. Now it got two assoc array and merge them together, when key conflict, right(last) value will be kept.
  5. array_merge(null, array()) returns array() and got a warning said, parameter #1 is not an array.

I post the code below to make things clear.

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;
}

//----------------------------------------------------------------

function is_index($a){
    $keys = array_keys($a);
    foreach($keys as $key) {
        $i = intval($key);
        if("$key"!="$i") return false;
    }
    return true;
}

function array_merge($a, $b){
    if(is_index($a)) $a = array_values($a);
    if(is_index($b)) $b = array_values($b);
    $results = array();
    if(is_index($a) and is_index($b)){
        foreach($a as $v) $results[] = $v;
        foreach($b as $v) $results[] = $v;
    }
    else{
        foreach($a as $k=>$v) $results[$k] = $v;
        foreach($b as $k=>$v) $results[$k] = $v;
    }
    return $results;
}
Community
  • 1
  • 1
Gucci Koo
  • 541
  • 4
  • 10
  • 2
    The example code is great, however hard to read. Would be much better if it was formatted correctly... – Yep_It's_Me Mar 12 '18 at 05:35
  • Indeed, your implementation is great, except that it doesn't give the same result as the built-in `array_merge` function. If you want to see the difference, compare the result of running `var_dump(array_merge(['a' => 1, 'b' => 2, 3, 4], ['a' => 5, 'b' => 6, 7, 8]));` with `var_dump(your_array_merge(['a' => 1, 'b' => 2, 3, 4], ['a' => 5, 'b' => 6, 7, 8]));` (I've renamed your implementation to `your_array_merge` to avoid function redefinition). The difference is that numeric and string keys of mixed arrays are treated differently in the original implementation. – Aleksander Z. Aug 08 '18 at 08:03