3
$array1 = [
    '1' => '11',
    'b' => 1,
    3   => 33,
    8   => 8
];
$array2 = [
    '1' => '22',
    'b' => 2,
    3   => 44,
    9   => 9
];

$merged = array_merge_recursive($array1, $array2);

and the result is:

array(7) {
  [0]=>
  string(2) "11"
  ["b"]=>
  array(2) {
    [0]=>
    int(1)
    [1]=>
    int(2)
  }
  [1]=>
  int(33)
  [2]=>
  int(8)
  [3]=>
  string(2) "22"
  [4]=>
  int(44)
  [5]=>
  int(9)
}

so lets take a glance: the only part is the 'b' keys, they are actually works. I dont want to overwrite anything of it but putting them together to an array. Thats good! But then keys the other numeric keys (int or string) are screwed up. I want to have this as result:

[
  '1' => ['11', '22']
  'b' => [1, 2]
  [3] => [33, 44]
  [8] => 8,
  [9] => 9
]

possible?

EDIT: of course keys "1" and 1 - string vs int key are the same

3
  • 1
    This is expected behavior of array_merge_recursive: If the input arrays have the same string keys, then the values for these keys are merged together into an array. If, however, the arrays have the same numeric key, the later value will not overwrite the original value, but will be appended. Commented Nov 21, 2016 at 16:55
  • 1
    You will probably have to do this manually instead of with a built-in function. Commented Nov 21, 2016 at 16:57
  • thats totally different... Commented Nov 21, 2016 at 19:00

2 Answers 2

7

Let's break down this question into to separate problems:

  1. When a key in the second array exist in the first array, you want to create an array and make the value the first element of that array.

To be honest, I don't know an easy way of solving this. I'm not sure there is one. And even if, I'm not sure you really want it. Such a function will lead to arrays having values that are a string or an array. How would you handle such an array?

Update: Well, there is one. Your example already shows that array_merge_recursive will convert values with a string key into an array. So 1 => 'foo' would be 0 => 'foo', but 'foo' => 'bar' will end up as 'foo' => ['bar']. I really don't understand this behaviour.

Using string keys would help you out in this case, but after learning more about array_merge_recursive I decided to avoid this function when possible. After I asked this question someone filed it as a bug in it since PHP 7.0, since it works differently in PHP 5.x.

  1. You want to keep the keys, while array_merge_resursive doesn't preserve integer keys, while it does for integer keys:

If the input arrays have the same string keys, then the values for these keys are merged together into an array, and this is done recursively, so that if one of the values is an array itself, the function will merge it with a corresponding entry in another array too. If, however, the arrays have the same numeric key, the later value will not overwrite the original value, but will be appended.

To make it worse, it handles differently when handling the nested arrays:

    $array1 = [30 => [500 => 'foo', 600 => 'bar']];
    $array2 = [];
    array_merge_recursive($array1, $array2);
    //[0 => [500=> 'foo', 600 => 'bar']];

So effectively, array_merge_resursive isn't really resursive.

Using array_replace_resursive solves that problem:

array_replace_recursive($array1, $array2);
//output: 
//array:5 [
//  1 => "22"
//  "b" => 2
//  3 => 44
//  8 => 8
//  9 => 9
//]

Please note that PHP is very consistent in being inconsistent. While array_merge_recursive isn't recursive, array_replace_recursive doesn't replace (it also appends):

If the key exists in the second array, and not the first, it will be created in the first array.

In many cases this is desired behavior and since naming functions isn't PHP's strongest point, you can consider this as a minor issue.

Sign up to request clarification or add additional context in comments.

2 Comments

Not exactly! array_replace_recursive doesn't always append. As per the docs, When the value in the first array is scalar, it will be replaced by the value in the second array, may it be scalar or array. When the value in the first array and the second array are both arrays, array_replace_recursive() will replace their respective value recursively. For this example by OP, values of $array1['b'] and $array2['b'] are both Array, so it works correctly there. Look at the other elements in the result, Scalar were replaced by Scalar and any non-existent keys were created.
"Please note that PHP is very consistent in being inconsistent" - Haha!
1

Can you rely on a native function to return your exact desired output? No. At least not in any version as of the date of this post (upto PHP8.1).

The good news is that crafting your own solution is very simple.

Code: (Demo)

foreach ($array2 as $key => $value) {
    if (!key_exists($key, $array1)) {
        $array1[$key] = $value;
    } else {
        $array1[$key] = (array)$array1[$key];
        $array1[$key][] = $value;
    }
}
var_export($array1);

I suppose I am less inclined to recommend this output structure because you have potentially different datatypes on a given level. If you were building subsequent code to iterate this data, you'd need to write conditions on every level to see if the data was iterable -- it just feels like you are setting yourself up for code bloat/convolution. I'd prefer a result which has consistent depth and datatypes.

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.