Array Unpacking with String Keys (PHP 8.1)
debt(d3/e1/b1/t5)
Closest to 'default linter catches the common case' (d3). Tools like Rector and PHPStan (listed in detection_hints.tools) can detect usage of array_merge() where spread operator would be cleaner, and can flag string-key spread usage on incompatible PHP versions. These are commonly configured tools in PHP projects, slightly more specialized than a basic linter but readily available, so d3 fits.
Closest to 'one-line patch or single-call swap' (e1). The quick_fix confirms this is a direct replacement: array_merge($defaults, $overrides) becomes [...$defaults, ...$overrides]. This is a single-expression swap with no structural change required.
Closest to 'minimal commitment' (b1). This is a syntax-level feature for array construction. It's a local expression-level choice that doesn't impose any structural weight on the codebase. Each usage is independent and trivially reversible back to array_merge().
Closest to 'notable trap' (t5). The misconception field identifies the key trap: developers assume the spread operator has always worked with string-keyed arrays, but it was only added in PHP 8.1 (PHP 7.4 only supported numeric keys). Additionally, common_mistakes notes that duplicate string keys in spread cause an error in PHP 8.1, unlike array_merge() where later values win — this contradicts the expected merge semantics that most PHP developers are familiar with. These are documented gotchas that most devs eventually learn.
Also Known As
TL;DR
Explanation
Prior to PHP 8.1, the spread operator (...) only worked with integer-keyed arrays — spreading an associative array caused a fatal error. PHP 8.1 lifted this restriction, enabling array merging as an alternative to array_merge(): $merged = [...$defaults, ...$overrides]. This is cleaner and slightly faster than array_merge() for simple cases. String key conflicts are resolved by last-write-wins, identical to array_merge() semantics. Combined with named argument spreading, this enables concise configuration merging and option-bag patterns common in framework APIs.
Common Misconception
Why It Matters
Common Mistakes
- Using array_merge() when the spread operator provides the same result with clearer intent for config overrides.
- Expecting later duplicate keys to win in spread operations — unlike array_merge, duplicate string keys in spread cause an error in PHP 8.1.
- Using numeric-keyed arrays with the spread operator expecting reindexing — behaviour differs from associative arrays.
- Not realising PHP 7 only supported numeric array unpacking — code using string key spread fails on PHP 7.
Code Examples
// Duplicate string key in spread — error in PHP 8.1:
$defaults = ['color' => 'blue', 'size' => 'M'];
$overrides = ['color' => 'red'];
$merged = [...$defaults, ...$overrides]; // Error: duplicate key 'color'
// Fix: use array_merge($defaults, $overrides) for override semantics
$defaults = ['timeout' => 30, 'retries' => 3];
$options = ['timeout' => 60];
$config = [...$defaults, ...$options]; // ['timeout'=>60,'retries'=>3]