← Home ← Codex ← DEBT ← Engine
Browse by Category
+ added · updated 7d
← Back to glossary

match() Exhaustiveness & UnhandledMatchError

PHP PHP 8.0+ Intermediate
debt(d5/e3/b3/t5)
d5 Detectability Operational debt — how invisible misuse is to your safety net

Closest to 'specialist tool catches' (d5). PHPStan and Psalm (cited in detection_hints.tools) at higher levels will catch missing match arms against enums, but this requires explicit configuration and isn't caught by default linters or the compiler itself.

e3 Effort Remediation debt — work required to fix once spotted

Closest to 'simple parameterised fix' (e3). The quick_fix indicates adding a default arm or ensuring all enum cases are handled — this is typically a localized change within one file, but may require reviewing the match logic and understanding the value space.

b3 Burden Structural debt — long-term weight of choosing wrong

Closest to 'localised tax' (b3). The choice of using match with or without default is confined to specific control-flow points. It doesn't impose system-wide architectural weight, but each match expression requires conscious decision about exhaustiveness strategy.

t5 Trap Cognitive debt — how counter-intuitive correct behaviour is

Closest to 'notable trap' (t5). The misconception states developers believe match without default is dangerous when the opposite is true — omitting default is intentional for safety. This contradicts intuition from switch statements where default feels like good practice, but it's a documented gotcha most PHP 8+ developers eventually learn.

About DEBT scoring →

Also Known As

exhaustive match match UnhandledMatchError match default

TL;DR

PHP 8's match expression throws UnhandledMatchError when no arm matches — enforcing exhaustiveness and eliminating silent fall-throughs.

Explanation

Unlike switch, PHP 8's match expression is strict in two ways: it uses strict comparison (===, not ==) and throws an UnhandledMatchError if no arm matches and there is no default. This transforms previously silent bugs — a switch with a missing case that fell through silently — into immediate, detectable failures. Add a default arm to handle unexpected values explicitly, or let the error surface during testing rather than silently misbehave in production. Static analysers (PHPStan, Psalm) can detect non-exhaustive match expressions against enum cases (PHP 8.1+), enforcing completeness at analysis time. Combine match with enum to get compile-time exhaustiveness guarantees.

Common Misconception

A match expression without a default arm is dangerous and should always have one. Omitting default is intentional when you want an UnhandledMatchError thrown for unexpected values — it is safer than a silent default that hides unhandled cases.

Why It Matters

PHP 8's match expression throws UnhandledMatchError for unmatched values — unlike switch, it enforces exhaustiveness at runtime and uses strict comparison, preventing silent fallthrough bugs.

Common Mistakes

  • Not providing a default arm for match expressions that may receive unexpected values in production.
  • Assuming match and switch are equivalent — match uses strict comparison (===), switch uses loose (==).
  • Not using match as a return value — it is an expression, eliminating the need for break and temporary variables.
  • Using match where the value space is open-ended (user input) without a default — UnhandledMatchError in production.

Code Examples

✗ Vulnerable
// switch with loose comparison and silent fallthrough:
switch ($code) {
    case '200': $status = 'OK'; break;   // '200' == 200 in switch
    case '404': $status = 'Not Found';   // Missing break — falls through!
    case '500': $status = 'Error'; break;
}

// match — strict, no fallthrough, expression:
$status = match((int)$code) {
    200 => 'OK', 404 => 'Not Found', 500 => 'Error',
    default => throw new InvalidArgumentException("Unknown code: $code")
};
✓ Fixed
$label = match($status) {
  Status::Active   => 'Active',
  Status::Inactive => 'Inactive',
  // UnhandledMatchError thrown for any other value — caught in tests
};

Added 15 Mar 2026
Edited 22 Mar 2026
Views 86
Rate this term
No ratings yet
🤖 AI Guestbook educational data only
| |
Last 30 days
0 pings W 0 pings T 0 pings F 0 pings S 0 pings S 1 ping M 0 pings T 1 ping W 0 pings T 0 pings F 0 pings S 0 pings S 1 ping M 0 pings T 2 pings W 1 ping T 0 pings F 0 pings S 0 pings S 1 ping M 0 pings T 0 pings W 0 pings T 0 pings F 0 pings S 0 pings S 0 pings M 1 ping T 1 ping W 0 pings T
No pings yet today
Ahrefs 1
Amazonbot 10 Ahrefs 9 Perplexity 5 SEMrush 5 ChatGPT 4 Scrapy 4 Google 3 Applebot 2 Brave Search 2 PetalBot 1 Twitter/X 1 Bing 1 Unknown AI 1
crawler 46 crawler_json 2
🧱 FUNDAMENTALS — new to this? Start with the ground floor.
PHP php A server-side scripting language that generates web pages and APIs — the code runs on the server, and only its output (usually HTML or JSON) reaches the browser.

PHP is often the first server-side language people meet, and understanding its execution model — script starts fresh on every request, no memory between requests — explains most of how the web backend works: sessions, databases, and caching all exist to bridge that per-request amnesia.

💡 Start with PHP 8.x, declare(strict_types=1), and PDO — skip any tutorial that mentions mysql_query().

Ask Codex about PHP →
DEV INTEL Tools & Severity
🟡 Medium ⚙ Fix effort: Low
⚡ Quick Fix
Use match expressions against enum cases — PHPStan at level 8+ will warn if you don't handle all cases; add a default only when you genuinely don't care about new values
📦 Applies To
PHP 8.0+ web cli queue-worker
🔗 Prerequisites
🔍 Detection Hints
match expression on enum without handling all cases; switch on enum without PHPStan exhaustiveness check
Auto-detectable: ✓ Yes phpstan psalm
🤖 AI Agent
Confidence: High False Positives: Low ✗ Manual fix Fix: Low Context: Function Tests: Update


✓ schema.org compliant