In PHP, what is the difference between array_merge() and the + union operator when both arrays share keys?
answer
- string keys: merge lets the later win
- union keeps the left-hand value
- merge renumbers integer keys from 0
- union never renumbers anything
- defaults pattern: $options + $defaults
basics
~10 sarray_merge() lets later arrays overwrite earlier ones for string keys but appends and renumbers integer keys; $a + $b keeps every key of $a, adds only keys missing from $a, and never renumbers.
solid answer
~40 s`array_merge(...$arrays)` walks the arrays left to right. For a **string** key present in several of them, the **last** value wins. **Integer** keys are never matched up: every integer-keyed value is appended and the result is renumbered from 0, so `array_merge([5 => 'a'], [5 => 'b'])` gives `[0 => 'a', 1 => 'b']`. The `+` operator is a **union**: it starts from the left array and adds only the keys the left array does not already have, for string and integer keys alike, keeping keys exactly as they are, so `[5 => 'a'] + [5 => 'b']` is `[5 => 'a']`. That makes `+` the natural tool for filling defaults (`$options + $defaults`) and for combining arrays keyed by IDs, while `array_merge()` suits concatenating lists or overriding configuration by name.
code
php · 14 lines<?php
$morning = ['croissant', 'baguette'];
$evening = ['brioche', 'rye'];
print_r(array_merge($morning, $evening)); // 0..3: all four items
print_r($morning + $evening); // croissant, baguette only
$byId = [1017 => 'Ana', 2044 => 'Ben'];
$more = [3001 => 'Chloe', 1017 => 'Ana M.'];
print_r(array_merge($byId, $more)); // [0 => Ana, 1 => Ben, 2 => Chloe, 3 => Ana M.]
print_r($byId + $more); // [1017 => Ana, 2044 => Ben, 3001 => Chloe]
$options = ['size' => 'large'];
$defaults = ['size' => 'medium', 'box' => true];
print_r($options + $defaults); // size => large, box => 1go deeper
Recall the two rules: array_merge() renumbers integer keys and lets later string keys win, while + keeps the left-hand value and every key.
Explain which one to use for lists, defaults and ID-keyed arrays, and where array_replace() fits when the right side should win without renumbering.
Catch merges that destroy ID keys or drop list items in review, and replace array_merge() inside loops with one spread merge at the end.
Set conventions for configuration and data merging, choosing explicit override semantics that stay correct when keys are numeric-looking IDs.
## Two ways to combine arrays PHP offers two everyday ways to combine arrays, and they answer different questions: - **`array_merge($a, $b, ...)`** asks: *what do I get if I lay these arrays end to end, letting later names override earlier ones?* - **`$a + $b`** asks: *what keys does `$a` have, and which of `$b`'s keys are missing from it?* The difference only matters when keys overlap or are integers, which is exactly when bugs appear. ## The rules side by side | Situation | `array_merge($a, $b)` | `$a + $b` | |---|---|---| | same string key in both | value from `$b` (later wins) | value from `$a` (left wins) | | same integer key in both | both values kept, appended | value from `$a`, `$b`'s ignored | | integer keys in the result | renumbered 0, 1, 2 ... | kept exactly as they were | | order of the result | `$a`'s elements, then `$b`'s | `$a`'s elements, then `$b`'s new keys | | more than two inputs | `array_merge($a, $b, $c)` | `$a + $b + $c` | | no inputs | `array_merge()` returns `[]` (since 7.4) | not applicable | ## Where each one fits **Concatenating lists** is `array_merge()` territory. Two lists of bakery orders `[0 => ..., 1 => ...]` and `[0 => ..., 1 => ...]` combine into one list with four elements numbered 0 to 3. With `+`, the second list's keys 0 and 1 already exist in the first, so its orders would silently vanish. **Filling defaults** is `+` territory. With `$options = ['size' => 'large'];` and `$defaults = ['size' => 'medium', 'box' => true];`, `$options + $defaults` keeps the caller's `'size'` and adds the missing `'box'`. `array_merge($defaults, $options)` also works for string keys, because the later array wins, but reads the other way round. **Arrays keyed by ID** are where `array_merge()` causes real damage. Suppose customers are keyed by numeric ID: 1. `$fromShop = [1017 => 'Ana', 2044 => 'Ben'];` 2. `$fromApp = [3001 => 'Chloe'];` 3. `array_merge($fromShop, $fromApp)` returns `[0 => 'Ana', 1 => 'Ben', 2 => 'Chloe']`: the IDs are gone. 4. `$fromShop + $fromApp` returns `[1017 => 'Ana', 2044 => 'Ben', 3001 => 'Chloe']`, which is what the code meant. If you want the right-hand value to win while still keeping integer keys, reverse the operands (`$fromApp + $fromShop`) or use `array_replace($fromShop, $fromApp)`, which overwrites by key without renumbering. ## Common mistakes - Using `array_merge()` inside a loop to accumulate (`$all = array_merge($all, $batch);`) copies the growing array on every iteration. Collect batches into a list and merge once with `array_merge(...$batches)`. - Expecting `+` to append a list to a list. It unions by key, so `[1, 2] + [3, 4, 5]` is `[1, 2, 5]`. - Forgetting that numeric-looking string keys such as `'1017'` are stored as integers, so they are renumbered by `array_merge()` too. - Reaching for `array_merge_recursive()` to merge nested configuration: it turns duplicate string keys into nested arrays of both values rather than overriding, which is rarely what configuration code wants. ## How to answer in an interview State the two rules crisply: `array_merge()` renumbers integer keys and lets later string keys win; `+` keeps the left-hand value for every duplicate key and never renumbers. Then give one example of each going wrong: `+` dropping a second list, `array_merge()` destroying ID keys. That shows you know not only the rule but also which one to choose.
- How do you combine two ID-keyed arrays so the right-hand values win without losing the IDs?Use `array_replace($left, $right)`, which overwrites by key and never renumbers, or reverse the union as `$right + $left`. Both keep integer keys intact, unlike `array_merge()`, which would renumber them from 0.
- Why is calling array_merge() inside a loop to accumulate results a performance problem?Each call builds a brand-new array containing everything accumulated so far, so the total copying grows with the square of the number of iterations. Collect the batches in a list and call `array_merge(...$batches)` once at the end.
saying these in an interview costs you the question
- The + operator appends the second list to the first.
- array_merge() keeps integer keys as they are.
- With +, the right-hand value wins for duplicate keys.
- array_merge() and + behave the same for string keys.
- array_merge_recursive() is the way to override nested configuration.