Null Coalescing ?? Operator (PHP 7.0)
debt(d3/e1/b1/t5)
Closest to 'default linter catches the common case' (d3). The detection_hints list rector and phpcs with an automated code_pattern `isset\([^)]+\)\s*\?`, meaning the common misuse (verbose isset ternary instead of ??) is caught by standard linting/sniffing tools without specialist configuration.
Closest to 'one-line patch or single-call swap' (e1). The quick_fix is explicit: replace `isset($x)?$x:$default` with `$x??$default`. This is a mechanical, single-expression substitution with no multi-file impact.
Closest to 'minimal commitment' (b1). The ?? operator is a local, expression-level syntactic choice. It imposes no structural debt on the codebase; each use is self-contained and its adoption or non-adoption doesn't shape the system's architecture or slow other work streams.
Closest to 'notable trap' (t5). The misconception field states exactly this trap: developers confuse ?? with ?:, not realising ?? only checks null/unset while ?: checks truthiness, meaning '' and 0 behave differently between the two. This is a documented gotcha (common_mistakes confirm it) that many PHP developers encounter, but it is a known, single-dimension distinction rather than a systemic contradiction.
TL;DR
Explanation
$a ?? $b returns $a if isset($a) and not null, else $b. PHP 7.4 added ??= (null coalescing assignment): $a ??= 'default' sets $a to 'default' if $a is null/unset. Chaining: $a ?? $b ?? $c ?? 'final'. Key behaviour: ?? doesn't suppress E_NOTICE for array access ($arr['key'] ?? null — no notice), unlike the ternary. Works with array nesting: $config['db']['host'] ?? 'localhost'. Compared to ?: (Elvis operator): ?: checks truthiness (falsy empty string triggers fallback); ?? checks null/unset only.
Common Misconception
Why It Matters
Common Mistakes
- Using ?: when 0 or '' should be preserved — use ?? instead.
- Not knowing $arr['missing'] ?? null suppresses the undefined key notice.
- Not using ??= for lazy initialization.
Code Examples
$name = isset($user['name']) ? $user['name'] : 'Guest';
$page = isset($_GET['page']) ? (int)$_GET['page'] : 1;
$name = $user['name'] ?? 'Guest';
$page = (int)($_GET['page'] ?? 1);
// PHP 7.4 assignment:
$cache ??= $this->loadFromDb();
// Chaining:
$host = $config['db']['host'] ?? $env['DB_HOST'] ?? 'localhost';