Friday, 27 March 2015

PHP: array_merge_recursive() vs. array_replace_recursive()

If you’ve been coding in PHP for a while, you have probably used array_merge() at some point. It’s been around since PHP 4, and like most PHP functions, it does largely what you’d expect it to do. If you have arrays with numeric indices, it re-indexes and appends subsequent arrays to the first array argument.
print_r(array_merge(
    array('a', 'b'),
    array('c', 'd')
));
/* the above will output:
Array
(
    [0] => a
    [1] => b
    [2] => c
    [3] => d
)
*/
If you have associative arrays, it doesn’t make much sense to re-index them. Instead, non-numeric keys are … well, merged. Keys from subsequent arrays will overwrite keys with the same name in earlier arrays.
/* note that the key 'B' appears in both arrays */
print_r(array_merge(
    array('A' => 1, 'B' => 2),
    array('B' => 20, 'C' => 30)
));
/* the above will output:
Array
(
    [A] => 1
    [B] => 20
    [C] => 30
)
*/
This is all pretty intuitive. But it gets trickier when you have nested associative arrays to merge. For example, you may have decoded the results from two JSON service calls into arrays, and they both have a top-level data key. array_merge() is not as useful in this case:
print_r(array_merge(
    array(
        'data' => array(
            'collision' => 'first',
            'unique1' => 1,
        )
    ),
    array(
        'data' => array(
            'collision' => 'second',
            'unique2' => 2,
        )
    )
));
/* the above will output:
Array
(
    [data] => Array
        (
            [collision] => second
            [unique2] => 2
        )
)
*/
The first array got clobbered — not quite what you expected, right? Fortunately, there’s a function that will do what you probably want: array_merge_recursive().
print_r(array_merge_recursive(
    array(
        'data' => array(
            'collision' => 'first',
            'unique1' => 1,
        )
    ),
    array(
        'data' => array(
            'collision' => 'second',
            'unique2' => 2,
        )
    )
));
/* the above will output:
Array
(
    [data] => Array
        (
            [collision] => Array
                (
                    [0] => first
                    [1] => second
                )
            [unique1] => 1
            [unique2] => 2
        )
)
*/
In some cases, this behavior isn’t actually what you want. One example is parsing hierarchical config files. If you had a default config and you wanted to merge in a user-specific config, you probably don’t want keys to be merged the way array_merge_recursive() does it. Instead, you would want the user-specific config to replace the default config’s value for that particular key. If you’re running PHP before version 5.3, you’d have to write a custom function to do this. But as of PHP 5.3, there is a new function that does exactly what you want: array_replace_recursive().
print_r(array_replace_recursive(
    array(
        'data' => array(
            'collision' => 'first',
            'unique1' => 1,
        )
    ),
    array(
        'data' => array(
            'collision' => 'second',
            'unique2' => 2,
        )
    )
));
/* the above will output:
Array
(
    [data] => Array
        (
            [collision] => second
            [unique1] => 1
            [unique2] => 2
        )
)
*/
If you’ve written a custom version of array_replace_recursive() and would like to switch to the built-in version, one helpful commenter suggests replacing your custom version with a wrapper that just calls array_replace_recursive(). There are also a few pure-PHP implementations of array_replace_recursive() if you’re stuck with an older version of PHP.

1 comment:

  1. This is exactly any revealing content along with being worthwhile and additionally skilled. accordingly. We want to make sure you with thanks for those results you earn in writing this Heroku Vs Aws . This is revealing page approximately checking and additionally getting to know words.

    ReplyDelete