Array merging in PHP
Correctly merging two arrays into a single array requires thinking about the type of data we have. Is our data flat or does it contain nested arrays? What should happen when both arrays contain the same key?
PHP provides three ways to merge arrays.
- The array union operator: +.
- The array_merge function.
- The array_merge_recursive function.
We may also need Zend\Stdlib\ArrayUtils::merge which ships as part of Zend Framework 2 and can be included in our application by requiring zendframework/zend-stdlib
with Composer.
Choosing the right function
Structure
When our data is flat we can use array_merge
or the +
operator. When we want to merge nested arrays we must use a recursive function like array_merge_recursive
or ArrayUtils::merge
.
Duplicates
Duplicates occur when both input arrays contain the same key. Only keys are considered when determining duplicates, not values. Duplicates create a merge conflict that is resolved by either appending or replacing duplicate key values.
Only the +
operator behaves consistently (it always replaces duplicates); the other merge functions change behaviour depending on whether the key type is numeric or a string as shown below. However, ArrayUtils::merge
will behave consistently when true
is passed as the third parameter since Zend Framework 2.2.6.
Numeric keys
With the exception of the +
operator, values in numeric keys are appended and reindexed. The +
operator always replaces duplicate keys regardless of the type.
Append | Replace | |
---|---|---|
Flat | array_merge | + |
Recursive |
array_merge_recursive
ArrayUtils::merge |
ArrayUtils::merge(x, y, true) |
Examples
In these examples both arrays have the same implicit numeric key (0). The +
operator drops duplicates found in the right operand.
[1] + [2];
[0 => 1]
The merge functions append values and reindex keys. Since the input arrays are flat in these examples, the result is the same for the recursive functions.
array_merge([1], [2]);
[0 => 1, 1 => 2]
String keys
With the exception of array_merge_recursive
, values in duplicate string keys are replaced. However, array_merge_recursive
always appends duplicate keys regardless of the type.
Append | Replace | |
---|---|---|
Flat |
array_merge
+ |
|
Recursive | array_merge_recursive | ArrayUtils::merge |
Examples
Like numeric keys, the +
operator always drops duplicates found in the right operand.
['foo' => 1] + ['foo' => 2];
['foo' => 1]
For string keys, array_merge
drops duplicates found in the first argument.
array_merge(['foo' => 1], ['foo' => 2]);
['foo' => 2]
array_merge_recursive
preserves duplicates by pushing each value into a new array under the duplicate key.
array_merge_recursive(['foo' => 1], ['foo' => 2]);
['foo' => [0 => 1, 1 => 2]]
Precedence
The argument for which duplicate keys are kept is said to have precedence during a merge. Argument order determines which values are kept and which are lost during replacement.
The +
operator gives precedence to the first operand but the other merge functions give precedence to the second argument as shown in the table below. Argument order for array_merge_recursive
is usually irrelevant since it always appends duplicates.
Function or operator | Precedence |
---|---|
+ | 1st operand |
array_merge | 2nd argument |
ArrayUtils::merge | 2nd argument |
Conclusion
To merge two arrays correctly we must consider the data structure of each array and how we want to handle conflicts that occur when both arrays contain the same key. Once we know the data structure and have chosen a duplicate handling strategy we can select the correct function to merge our arrays.
Finally we ensure our arguments are specified in the correct order to give precedence to the array whose data we wish to keep when conflicts occur.