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.

  1. The array union operator: +.
  2. The array_merge function.
  3. 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.


Comments