Skip to content

Instantly share code, notes, and snippets.

@nl5887
Created November 2, 2015 15:03
Show Gist options
  • Select an option

  • Save nl5887/9bc6880dad1344b00bd2 to your computer and use it in GitHub Desktop.

Select an option

Save nl5887/9bc6880dad1344b00bd2 to your computer and use it in GitHub Desktop.
PHP Deep merge function with filter
<?php
// based on drupal_array_merge_deep_array
function MergeDeep($arrays, $filterFn = null) {
return _merge_deep_array($arrays, "", 1, $filterFn);
}
function _merge_deep_array($arrays, $path, $depth, $filterFn) {
// detect if associative or sequential array
if (array_values($arrays) !== $arrays) {
return _merge_deep_array(array($arrays), $path, $depth, $filterFn);
}
$result = array();
foreach ($arrays as $array) {
foreach ($array as $key => $value) {
// Renumber integer keys as array_merge_recursive() does. Note that PHP
// automatically converts array keys that are integer strings (e.g., '1')
// to integers.
$subpath = (strlen($path) > 0?$path . "." . $key:$key);
if (!is_null($filterFn) && !$filterFn($subpath, $value, $depth)) {
continue;
}
// TODO: this doesn't work always, imagine 4 => value, 6 => value. It will just count 1 => value, 2 => value.
if (is_integer($key)) {
$result[] = $value;
}
// Recurse when both values are arrays.
elseif (isset($result[$key]) && is_array($result[$key]) && is_array($value)) {
$result[$key] = _merge_deep_array(array($result[$key], $value), $subpath, $depth + 1, $filterFn);
} elseif (is_array($value)) {
$result[$key] = _merge_deep_array(array($value), $subpath, $depth + 1, $filterFn);
}
// Otherwise, use the latter value, overriding any previous value.
else {
$result[$key] = $value;
}
}
}
return $result;
}
class MergeDeepTest extends PHPUnit_Framework_TestCase
{
var $src = array(
'a' => 'b',
'b' => array(
'c' => 9,
'd' => null,
'e' => array(
'f' => array('g', 'h'),
'i' => 'j'
)
)
);
public function testComplexObject()
{
$result = MergeDeep($this->src);
print_r($result);
// using json_encoder to compare objects
return json_encode($this->src) === json_encode($result);
}
public function testFilterFunction()
{
$result = MergeDeep($this->src, function($path, $value, $depth) {
// return only path a
return ($path === 'a');
});
print_r($result);
// using json_encoder to compare objects
return json_encode($this->src) === json_encode($result);
}
public function testFilterDeepFunction()
{
$result = MergeDeep($this->src, function($path, $value, $depth) {
// return everything except b.e.f
return ($path !== 'b.e.f');
});
print_r($result);
// using json_encoder to compare objects
return json_encode($this->src) === json_encode($result);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment