I ran into a fairly unique situation where array_merge_recursive ALMOST did what I wanted, but NOT QUITE. I read through all of the comments, and I didn't find anything that really helped me. I saw a lot of functions submitted that were just trying to recreate array_replace_recursive. This is not that.
Take a look at the code and try it out. Hopefully it helps someone in need!
class Arr
{
/**
* Merge multiple arrays.
*
* This is similar to, but slightly different than array_merge_recursive.
* The main difference is that it will merge like keys in subarrays,
* instead of simply pushing them into the output array.
*
* @param array ...$array
*
* @return array
*/
public static function merge()
{
/** Initialize the output array */
$merged = [];
/** Go through each argument */
foreach (func_get_args() as $array) {
/** Go through each key/value of this array */
foreach ($array as $key => $value) {
/**
* If this key isn't set on merged,
* then it needs to be set for the first time
*/
if (! isset($merged[$key])) {
/**
* Before we can set it, we must make sure
* to dive into this value if it is an array,
* so that all of its children will be processed.
*/
if (is_array($value)) {
$value = static::merge($value);
}
/**
* Now that we're happy with this value,
* and we're sure that, if it is an array,
* all of its children have been processed,
* let's go ahead and set it.
*/
$merged[$key] = $value;
/** We can skip the rest of the loop */
continue;
}
/**
* We're here because we want to set a key
* that is already set on merged. We don't want
* to overwrite anything - we want to add to it.
* So, we need to make sure that we're working with an array.
*/
if (! is_array($merged[$key])) {
$merged[$key] = [$merged[$key]];
}
/**
* Before we push the value onto the array,
* we need to check to see if it is an array itself.
* If it is, then we need to make sure all of its children
* are processed. We do this by merging all of the children
* together. This is where it differs from array_merge_recursive,
* which would simply push the children onto the end of the array.
*/
if (is_array($value)) {
$value = forward_static_call_array([Arr::class, 'merge'], $value);
}
/** Now we're ready to push the value into merged */
$merged[$key][] = $value;
}
}
/** Return the merged array */
return $merged;
}
}