php.net |  support |  documentation |  report a bug |  advanced search |  search howto |  statistics |  random bug |  login
Doc Bug #34834 array_merge_recursive() merges arrays with objects with arrays
Submitted: 2005-10-11 23:35 UTC Modified: 2021-09-14 15:06 UTC
Votes:10
Avg. Score:3.5 ± 1.7
Reproduced:5 of 6 (83.3%)
Same Version:1 (20.0%)
Same OS:4 (80.0%)
From: tomas_matousek at hotmail dot com Assigned:
Status: Verified Package: Arrays related
PHP Version: 5CVS-2005-11-02 (cvs) OS: *
Private report: No CVE-ID: None
 [2005-10-11 23:35 UTC] tomas_matousek at hotmail dot com
Description:
------------
Although one cannot pass obejects to array_merge_recursive() function, it looks like it doesn't ignore objects at all.
If objects are contained in the array it merges them as if they were arrays of fields. I think it is not good to treat objects in this way when other array functions doesn't do so (e.g. array_walk_recursive doesn't step to fields of objects).

Reproduce code:
---------------
class A 
{ 
  var $field = array(1);
}

$a = new A;
$x = array("a" => $a);

$y = array("a" => array("field" => array(2)));

var_dump(array_merge_recursive($x,$y));

Expected result:
----------------
array(1) {
  ["a"]=>
  array(2) {
    [0]=>
    object(A)#1 (1) {
      ["field"]=>
      array(1) {
        [0]=>
        int(1)
      }
    }
    ["field"]=>
    array(1) {
      [0]=>
      int(2)
    }
  }
}


Actual result:
--------------
array(1) {
  ["a"]=>
  array(1) {
    ["field"]=>
    array(2) {
      [0]=>
      int(1)
      [1]=>
      int(2)
    }
  }
}


Patches

Pull Requests

History

AllCommentsChangesGit/SVN commitsRelated reports
 [2015-11-04 09:49 UTC] saboteur at saboteur dot me
You get even more interesting result using datetime.

Code:
-------
<?php

$old = ['created' => new \DateTime()];
$new = ['created' => new \DateTime('+1 minute')];

$changeset = array_merge_recursive($old, $new);

var_dump($changeset);

Expected:
---------
array(1) {
  ["created"]=>
  array(2) {
    [0] => object(DateTime)#1 (3) {
      ["date"]=>
        string(26) "2015-11-04 10:36:03.000000"
      ["timezone_type"]=>
        int(3)
      ["timezone"]=>
        string(16) "Europe/Amsterdam"
    },
    [1] => object(DateTime)#1 (3) {
      ["date"]=>
        string(26) "2015-11-04 10:37:03.000000"
      ["timezone_type"]=>
        int(3)
      ["timezone"]=>
        string(16) "Europe/Amsterdam"
    }
  }
}

Actual
-------
array(1) {
  ["created"]=>
  array(3) {
    ["date"]=>
    array(2) {
      [0]=>
      string(26) "2015-11-04 10:36:03.000000"
      [1]=>
      string(26) "2015-11-04 10:37:03.000000"
    }
    ["timezone_type"]=>
    array(2) {
      [0]=>
      int(3)
      [1]=>
      int(3)
    }
    ["timezone"]=>
    array(2) {
      [0]=>
      string(16) "Europe/Amsterdam"
      [1]=>
      string(16) "Europe/Amsterdam"
    }
  }
}

So that treats DateTime as array.
 [2016-12-30 23:10 UTC] cmb@php.net
-Package: Feature/Change Request +Package: Arrays related
 [2021-09-14 15:06 UTC] cmb@php.net
-Type: Feature/Change Request +Type: Documentation Problem
 [2021-09-14 15:06 UTC] cmb@php.net
I have to admit that this behavior[1] is unintuitive, and might
not have been the best design decision.  However, changing it
after so many years is likely to break code which relies on it. As
such, this should go through the RFC process[2].  Anybody is
welcome to pursue it.

Anyhow, more important than to change the behavior, is to properly
document it.  There is no indication on the man page[3], so I'm
changing this ticket to documentation problem.

[1] <https://3v4l.org/vmrnK>
[2] <https://wiki.php.net/rfc/howto>
[3] <https://www.php.net/array_merge_recursive>
 
PHP Copyright © 2001-2024 The PHP Group
All rights reserved.
Last updated: Tue Nov 05 09:01:29 2024 UTC