Clobbering lacks support for merging non-associative array values
colinodell opened this issue · comments
Data::import()
, Data::importData()
, and Util::mergeAssocArray()
support this notion of "clobbering" when trying to merge in two arrays. In a nutshell:
$clobber Value |
Behavior |
---|---|
false |
Values from the original array are preserved |
true |
Values from the second array overwrite the first |
For example:
$a = ['x' => 'a', 'foo' => ['foo'], 'a' => true];
$b = ['x' => 'b', 'foo' => ['bar'], 'b' => true];
Util::mergeAssocArray($a, $b, false);
// ['x' => 'a', 'foo' => ['foo'], 'a' => true, 'b' => true]
Util::mergeAssocArray($a, $b, true);
// ['x' => 'b', 'foo' => ['bar'], 'a' => true, 'b' => true]
However, there's no ability to merge non-associative array values. In the example above, it's impossible for me to have the foo
key contain ['foo', 'bar')
.
To give a more realistic example, I might have Data
elements representing HTML tag attributes:
$attributes = [
'id' => 'logo',
'class' => ['img-responsive'],
'alt' => 'My logo',
];
And I want to merge in some additional attributes:
$more = [
'class' => ['box-shadow'],
'alt' => 'Our Awesome Logo',
];
In order to get this output:
[
'id' => 'logo',
'class' => ['img-responsive', 'box-shadow'],
'alt' => 'Our Awesome Logo',
];
Unfortunately neither $clobber
mode allows this.
Proposal
Add a third mode which acts more like PHP's array_merge()
function - it will clobber things with string keys but append things with numeric keys.
To do this, we'll create three constants, one for each mode:
public const PRESERVE = 0; // equivalent to `false` in 1.x
public const REPLACE = 1; // equivalent to `true` in 1.x; default value
public const MERGE = 2; // the new approach I'm proposing
We'd also rename $clobber
to $mode
since it's no longer all-or-nothing.
This approach provides some level of backward-compatibility for anyone not using strict types, as false
gets coerced to 0
and true
gets coerced to 1
.