Created
November 2, 2015 15:03
-
-
Save nl5887/9bc6880dad1344b00bd2 to your computer and use it in GitHub Desktop.
PHP Deep merge function with filter
This file contains hidden or 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 | |
| // 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