diff --git a/docs/guide/helper-array.md b/docs/guide/helper-array.md
index df4fcce176..2552816835 100644
--- a/docs/guide/helper-array.md
+++ b/docs/guide/helper-array.md
@@ -303,21 +303,68 @@ Encoding will use application charset and could be changed via third argument.
## Merging Arrays
+You can use [[yii\helpers\ArrayHelper::merge()|ArrayHelper::merge()]] to merge two or more arrays into one recursively.
+If each array has an element with the same string key value, the latter will overwrite the former
+(different from [array_merge_recursive()](http://php.net/manual/en/function.array-merge-recursive.php)).
+Recursive merging will be conducted if both arrays have an element of array type and are having the same key.
+For integer-keyed elements, the elements from the latter array will be appended to the former array.
+You can use [[yii\helpers\UnsetArrayValue]] object to unset value from previous array or
+[[yii\helpers\ReplaceArrayValue]] to force replace former value instead of recursive merging.
+
+For example:
+
```php
- /**
- * Merges two or more arrays into one recursively.
- * If each array has an element with the same string key value, the latter
- * will overwrite the former (different from array_merge_recursive).
- * Recursive merging will be conducted if both arrays have an element of array
- * type and are having the same key.
- * For integer-keyed elements, the elements from the latter array will
- * be appended to the former array.
- * @param array $a array to be merged to
- * @param array $b array to be merged from. You can specify additional
- * arrays via third argument, fourth argument etc.
- * @return array the merged array (the original arrays are not changed.)
- */
- public static function merge($a, $b)
+$array1 = [
+ 'name' => 'Yii',
+ 'version' => '1.1',
+ 'ids' => [
+ 1,
+ ],
+ 'validDomains' => [
+ 'example.com',
+ 'www.example.com',
+ ],
+ 'emails' => [
+ 'admin' => 'admin@example.com',
+ 'dev' => 'dev@example.com',
+ ],
+];
+
+$array2 = [
+ 'version' => '2.0',
+ 'ids' => [
+ 2,
+ ],
+ 'validDomains' => new \yii\helpers\ReplaceArrayValue([
+ 'yiiframework.com',
+ 'www.yiiframework.com',
+ ]),
+ 'emails' => [
+ 'dev' => new \yii\helpers\UnsetArrayValue(),
+ ],
+];
+
+$result = ArrayHelper::merge($array1, $array2);
+```
+
+The result will be:
+
+```php
+[
+ 'name' => 'Yii',
+ 'version' => '2.0',
+ 'ids' => [
+ 1,
+ 2,
+ ],
+ 'validDomains' => [
+ 'yiiframework.com',
+ 'www.yiiframework.com',
+ ],
+ 'emails' => [
+ 'admin' => 'admin@example.com',
+ ],
+]
```
diff --git a/framework/CHANGELOG.md b/framework/CHANGELOG.md
index ebbff08cab..0e93ff999a 100644
--- a/framework/CHANGELOG.md
+++ b/framework/CHANGELOG.md
@@ -9,6 +9,7 @@ Yii Framework 2 Change Log
- Bug #11912: Fixed PostgreSQL Schema to support negative default values for integer/float/decimal columns (nsknewbie)
- Bug #11947: Fixed `gridData` initialization in `yii.gridView.js` (pavlm)
- Bug #11949: Fixed `ActiveField::end` generates close tag when it's `option['tag']` is null (egorio)
+- Enh #11275: Added possibility of unset or force replace former value in `ArrayHelper::merge()` (mdmunir, rob006)
- Enh #11950: Improve BaseArrayHelper::keyExists speed (egorio)
- Bug #11726: `DbSession` was echoing database errors in production mode (samdark, pastuhov, deadkrolik)
- Bug #12030: Fixed `yii\base\Model::offsetExists()` throws an exception on un-existing field (klimov-paul)
diff --git a/framework/helpers/BaseArrayHelper.php b/framework/helpers/BaseArrayHelper.php
index 1968772939..48ca2faccf 100644
--- a/framework/helpers/BaseArrayHelper.php
+++ b/framework/helpers/BaseArrayHelper.php
@@ -107,6 +107,8 @@ class BaseArrayHelper
* type and are having the same key.
* For integer-keyed elements, the elements from the latter array will
* be appended to the former array.
+ * You can use [[UnsetArrayValue]] object to unset value from previous array or
+ * [[ReplaceArrayValue]] to force replace former value instead of recursive merging.
* @param array $a array to be merged to
* @param array $b array to be merged from. You can specify additional
* arrays via third argument, fourth argument etc.
@@ -119,7 +121,11 @@ class BaseArrayHelper
while (!empty($args)) {
$next = array_shift($args);
foreach ($next as $k => $v) {
- if (is_int($k)) {
+ if ($v instanceof UnsetArrayValue) {
+ unset($res[$k]);
+ } elseif ($v instanceof ReplaceArrayValue) {
+ $res[$k] = $v->value;
+ } elseif (is_int($k)) {
if (isset($res[$k])) {
$res[] = $v;
} else {
diff --git a/framework/helpers/ReplaceArrayValue.php b/framework/helpers/ReplaceArrayValue.php
new file mode 100644
index 0000000000..48644cf2be
--- /dev/null
+++ b/framework/helpers/ReplaceArrayValue.php
@@ -0,0 +1,73 @@
+ [
+ * 1,
+ * ],
+ * 'validDomains' => [
+ * 'example.com',
+ * 'www.example.com',
+ * ],
+ * ];
+ *
+ * $array2 = [
+ * 'ids' => [
+ * 2,
+ * ],
+ * 'validDomains' => new \yii\helpers\ReplaceArrayValue([
+ * 'yiiframework.com',
+ * 'www.yiiframework.com',
+ * ]),
+ * ];
+ *
+ * $result = \yii\helpers\ArrayHelper::merge($array1, $array2);
+ * ```
+ *
+ * The result will be
+ *
+ * ```php
+ * [
+ * 'ids' => [
+ * 1,
+ * 2,
+ * ],
+ * 'validDomains' => [
+ * 'yiiframework.com',
+ * 'www.yiiframework.com',
+ * ],
+ * ]
+ * ```
+ *
+ * @author Robert Korulczyk
+ * @since 2.0.10
+ */
+class ReplaceArrayValue
+{
+ /**
+ * @var mixed value used as replacement.
+ */
+ public $value;
+
+ /**
+ * Constructor.
+ * @param mixed $value value used as replacement.
+ */
+ public function __construct($value)
+ {
+ $this->value = $value;
+ }
+}
diff --git a/framework/helpers/UnsetArrayValue.php b/framework/helpers/UnsetArrayValue.php
new file mode 100644
index 0000000000..0cb48021ac
--- /dev/null
+++ b/framework/helpers/UnsetArrayValue.php
@@ -0,0 +1,53 @@
+ [
+ * 1,
+ * ],
+ * 'validDomains' => [
+ * 'example.com',
+ * 'www.example.com',
+ * ],
+ * ];
+ *
+ * $array2 = [
+ * 'ids' => [
+ * 2,
+ * ],
+ * 'validDomains' => new \yii\helpers\UnsetArrayValue(),
+ * ];
+ *
+ * $result = \yii\helpers\ArrayHelper::merge($array1, $array2);
+ * ```
+ *
+ * The result will be
+ *
+ * ```php
+ * [
+ * 'ids' => [
+ * 1,
+ * 2,
+ * ],
+ * ]
+ * ```
+ *
+ * @author Robert Korulczyk
+ * @since 2.0.10
+ */
+class UnsetArrayValue
+{
+}
diff --git a/tests/framework/helpers/ArrayHelperTest.php b/tests/framework/helpers/ArrayHelperTest.php
index c8a89c3c97..16184ddde9 100644
--- a/tests/framework/helpers/ArrayHelperTest.php
+++ b/tests/framework/helpers/ArrayHelperTest.php
@@ -307,6 +307,79 @@ class ArrayHelperTest extends TestCase
$this->assertEquals($expected, $result);
}
+ public function testMergeWithUnset()
+ {
+ $a = [
+ 'name' => 'Yii',
+ 'version' => '1.0',
+ 'options' => [
+ 'namespace' => false,
+ 'unittest' => false,
+ ],
+ 'features' => [
+ 'mvc',
+ ],
+ ];
+ $b = [
+ 'version' => '1.1',
+ 'options' => new \yii\helpers\UnsetArrayValue(),
+ 'features' => [
+ 'gii',
+ ],
+ ];
+
+ $result = ArrayHelper::merge($a, $b);
+ $expected = [
+ 'name' => 'Yii',
+ 'version' => '1.1',
+ 'features' => [
+ 'mvc',
+ 'gii',
+ ],
+ ];
+
+ $this->assertEquals($expected, $result);
+ }
+
+ public function testMergeWithReplace()
+ {
+ $a = [
+ 'name' => 'Yii',
+ 'version' => '1.0',
+ 'options' => [
+ 'namespace' => false,
+ 'unittest' => false,
+ ],
+ 'features' => [
+ 'mvc',
+ ],
+ ];
+ $b = [
+ 'version' => '1.1',
+ 'options' => [
+ 'unittest' => true,
+ ],
+ 'features' => new \yii\helpers\ReplaceArrayValue([
+ 'gii',
+ ]),
+ ];
+
+ $result = ArrayHelper::merge($a, $b);
+ $expected = [
+ 'name' => 'Yii',
+ 'version' => '1.1',
+ 'options' => [
+ 'namespace' => false,
+ 'unittest' => true,
+ ],
+ 'features' => [
+ 'gii',
+ ],
+ ];
+
+ $this->assertEquals($expected, $result);
+ }
+
/**
* @see https://github.com/yiisoft/yii2/pull/11549
*/