Created
March 6, 2020 22:07
-
-
Save dsantuc/aec254b82cce443c9db0ea49d076cad2 to your computer and use it in GitHub Desktop.
A more intuitive implementation of PHP's array_merge_recursive()
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
function ds_array_merge_recursive () { | |
$args = func_get_args(); | |
$numArgs = count($args); | |
if ($numArgs < 1) { | |
trigger_error(__FUNCTION__ . "() expects at least one parameter, $numArgs given", E_USER_WARNING); | |
return null; | |
} | |
foreach ($args as $i=>$arg) { | |
if (!is_array($arg)) { | |
$type = gettype($arg); | |
$argNum = $i+1; | |
trigger_error(__FUNCTION__ . "(): Expected parameter $argNum to be an array, $type given", E_USER_WARNING); | |
return null; | |
} | |
} | |
if ($numArgs < 2) { | |
return $args[0]; | |
} | |
if ($numArgs > 2) { | |
$dest = array_shift($args); | |
return ds_array_merge_recursive($dest, call_user_func_array('ds_array_merge_recursive', $args)); | |
} | |
$dest = array_shift($args); | |
$src = array_shift($args); | |
foreach ($src as $key=>$value) { | |
if (is_int($key)) { | |
$dest[] = $value; | |
} | |
elseif (array_key_exists($key, $dest) && is_array($dest[$key]) && is_array($value)) { | |
$dest[$key] = ds_array_merge_recursive($dest[$key], $value); | |
} | |
else { | |
$dest[$key] = $value; | |
} | |
} | |
return $dest; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
When merging data into an array, PHP's
array_merge()
overwrites values with the same string key from right to left. Most of the time, this is fine, but if the value sharing the same key happens to be an array,array_merge()
overwrites the whole array. There is a function calledarray_merge_recursive()
which merges sub arrays recursively, but it does so in a strange way: instead of overwriting the destination array's value, it creates an array with the values from both arrays.For example, consider the following arrays:
Each has a sub-array with the key
'foo'
, each of which in turn has some keys that are unique, but some that are shared.Merging these arrays with
array_merge()
produces this result:The
'foo'
sub array from$a3
overwrites those from the first two arrays.Merging with
array_merge_recursive()
does this:$foo['a']
and$foo['b']
are unique to$a1
, so those values are preserved.$foo['c']
is shared between$a1
and$a2
, so we get an array with both values.$foo['d']
is unique to$a2
, so that stays as is, but$foo['e']
is shared between$a2
and$a3
, so again we get an array, and finally$foo['f']
and$foo['g']
are unique to$a3
, so those values are preserved.I humbly put it to you, dear reader, that this is not what most people want or expect. I would have expected the values with unique keys to be preserved, but those with shared keys to be overwritten from right to left, as in
array_merge()
.ds_array_merge_recursive()
aims to implement this behavior:It can accept an arbitrary number of arrays and returns null when called with no arguments or with non-array arguments, emitting a warning (just like
array_merge()
andarray_merge_recursive()
), but I think it does more of the Right Thing™ (or at least the expected thing) with respect to duplicated string keys.