diff --git a/src/utils/__tests__/PhutilUtilsTestCase.php b/src/utils/__tests__/PhutilUtilsTestCase.php --- a/src/utils/__tests__/PhutilUtilsTestCase.php +++ b/src/utils/__tests__/PhutilUtilsTestCase.php @@ -389,6 +389,62 @@ $this->assertEqual(array('x' => 'x'), array_fuse(array('x'))); } + public function testArrayMergeRecursiveOverrule() { + $cases = array( + array( + 'original' => array('foo'), + 'overrule' => array(), + 'result' => array('foo') + ), + array( + 'original' => array(), + 'overrule' => array('foo'), + 'result' => array('foo') + ), + array( + 'original' => array('bar'), + 'overrule' => array('foo'), + 'result' => array('foo') + ), + array( + 'original' => array('bar' => 1), + 'overrule' => array('foo' => 2), + 'result' => array('bar' => 1, 'foo' => 2) + ), + array( + 'original' => array('bar' => 1), + 'overrule' => array('bar' => 2), + 'result' => array('bar' => 2) + ), + array( + 'original' => array('bar' => 1, 'bar-1' => 'stringValue'), + 'overrule' => array('foo' => 2), + 'result' => array('bar' => 1, 'bar-1' => 'stringValue', 'foo' => 2) + ), + array( + 'original' => array('bar' => array('foo')), + 'overrule' => array('bar' => 2), + 'result' => array('bar' => 2) + ), + array( + 'original' => array('bar' => array('foo')), + 'overrule' => array('bar' => array('bar')), + 'result' => array('bar' => array('bar')) + ), + array( + 'original' => array('bar' => array('bar' => 1, 'foo' => 1)), + 'overrule' => array('bar' => array('bar' => 2)), + 'result' => array('bar' => array('bar' => 2, 'foo' => 1)) + ) + ); + + foreach ($cases as $case) { + $this->assertEqual( + array_merge_recursive_overrule( + $case['original'], $case['overrule']), $case['result']); + } + } + public function testArrayInterleave() { $this->assertEqual(array(), array_interleave('x', array())); $this->assertEqual(array('y'), array_interleave('x', array('y'))); diff --git a/src/utils/utils.php b/src/utils/utils.php --- a/src/utils/utils.php +++ b/src/utils/utils.php @@ -735,6 +735,36 @@ return call_user_func_array('array_merge', $arrayv); } +/** + * Merges two arrays recursively and "binary safe" (integer keys are overridden + * as well), overruling similar values in the original array with the values of + * the overrule array. In case of identical keys, ie. keeping the values of the + * overrule array. + * + * The differences to the existing PHP function array_merge_recursive() is that + * elements or the original array get overwritten if the same key is present in + * the overrule array. + * + * @param array Array with the original values + * @param array Array with the values that should overrule the values + * from the original array + * @return array the overruled array + */ +function array_merge_recursive_overrule(array $original, array $overrule) { + foreach (array_keys($overrule) as $key) { + if (isset( + $original[$key]) && + is_array($original[$key]) && + is_array($overrule[$key])) { + $original[$key] = array_merge_recursive_overrule( + $original[$key], $overrule[$key]); + } else { + $original[$key] = $overrule[$key]; + } + } + + return $original; +} /** * Split a corpus of text into lines. This function splits on "\n", "\r\n", or