title: Why is array_merge_recursive not recursive?
body: <p>I recently found a bug in my application caused by unexpected behaviour of <code>array_merge_recursive</code>. Let's take a look at this simple example:</p>
  
  <pre><code>$array1 = [
      1 =&gt; [
          1 =&gt; 100,
          2 =&gt; 200,
      ],
      2 =&gt; [
          3 =&gt; 1000,
      ],
      3 =&gt; [
          1 =&gt; 500
      ]
  ];
  $array2 = [
      3 =&gt; [
          1 =&gt; 500
      ]
  ];
  array_merge_recursive($array1, $array2);
  //returns: array:4 [ 0 =&gt; //...
  </code></pre>
  
  <p>I expected to get an array with 3 elements: keys 1, 2, and 3. However, the function returns an array with keys 0, 1, 2 and 3. So 4 elements, while I expected only 3. When I replace the numbers by their alphabetical equivalents (a, b, c) it returns an array with only 3 elements: a, b and c.</p>
  
  <pre><code>$array1 = [
      'a' =&gt; [
          1 =&gt; 100,
          2 =&gt; 200,
      ],
      'b' =&gt; [
          3 =&gt; 1000,
      ],
      'c' =&gt; [
          1 =&gt; 500
      ]
  ];
  $array2 = [
      'c' =&gt; [
          1 =&gt; 500
      ]
  ];
  array_merge_recursive($array1, $array2);
  //returns: array:3 [ 'a' =&gt; //...
  </code></pre>
  
  <p>This is (to me at least) unexpected behaviour, but at least it's documented:</p>
  
  <blockquote>
    <p><a href="http://php.net/manual/en/function.array-merge-recursive.php" rel="nofollow noreferrer">http://php.net/manual/en/function.array-merge-recursive.php</a></p>
    
    <p>If the input arrays have the same <strong>string keys</strong>, then the values for
    these keys are <strong>merged</strong> 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 <strong>same numeric key</strong>, the later
    value will not overwrite the original value, but will be <strong>appended</strong>.</p>
  </blockquote>
  
  <p>The documentation isn't very clear about what 'appended' means. It turns out that elements of <code>$array1</code> with a numeric key will be treated as indexed elements, so they'll lose there current key: the returned array starts with 0. This will lead to strange outcome when using both numeric and string keys in an array, but let's not blame PHP if you're using a bad practice like that. In my case, the problem was solved by using <code>array_replace_recursive</code> instead, which did the expected trick. ('replace' in that function means replace if exist, append otherwise; naming functions is hard!)</p>
  
  <h1>Question 1: recursive or not?</h1>
  
  <p>But that's not were this question ends. I thought <code>array_*_resursive</code> would be a recursive function: </p>
  
  <blockquote>
    <p>Recursion is a kind of function call in which a function calls itself.
    Such functions are also called recursive functions. Structural
    recursion is a method of problem solving where the solution to a
    problem depends on solutions to smaller instances of the same problem.</p>
  </blockquote>
  
  <p>It turns out it isn't. While <code>$array1</code> and <code>$array2</code> are associative arrays, both <code>$array1['c']</code> and <code>$array2['c']</code> from the example above are indexed arrays with one element: <code>[1 =&gt; 500]</code>. Let's merge them:</p>
  
  <pre><code>array_merge_recursive($array1['c'], $array2['c']);
  //output: array:2 [0 =&gt; 500, 1 =&gt; 500]
  </code></pre>
  
  <p>This is expected output, because both arrays have a numeric key (<code>1</code>), so the second will be appended to the first. The new array starts with key 0. But let's get back to the very first example:</p>
  
  <pre><code>array_merge_recursive($array1, $array2);
  // output:
  // array:3 [
  //  "a" =&gt; array:2 [
  //    1 =&gt; 100
  //    2 =&gt; 200
  //  ]
  //  "b" =&gt; array:1 [
  //    3 =&gt; 1000
  //  ]
  //  "c" =&gt; array:2 [
  //    1 =&gt; 500 //&lt;-- why not 0 =&gt; 500?
  //    2 =&gt; 500
  //  ]
  //]
  </code></pre>
  
  <p><code>$array2['c'][1]</code> is appended to <code>$array1['c']</code> but it has keys 1 and 2. Not 0 and 1 in the previous example. The main array and it's sub-arrays are treated differently when handling integer keys.  </p>
  
  <h1>Question 2: String or integer key makes a big difference.</h1>
  
  <p>While writing this question, I found something else. It's getting more confusing when replacing the numeric key with a string key in a sub-array:</p>
  
  <pre><code>$array1 = [
      'c' =&gt; [
          'a' =&gt; 500
      ]
  ];
  $array2 = [
      'c' =&gt; [
          'a' =&gt; 500
      ]
  ];
  array_merge_recursive($array1, $array2);
  // output:
  // array:1 [
  //  "c" =&gt; array:1 [
  //    "a" =&gt; array:2 [
  //      0 =&gt; 500
  //      1 =&gt; 500
  //    ]
  //  ]
  //]
  </code></pre>
  
  <p>So using a string key will cast <code>(int) 500</code> into <code>array(500)</code>, while using a integer key won't. </p>
  
  <p>Can someone explain this behaviour?</p>