switch vs match — exhaustiveness, strict comparison
Concept
switch and match both dispatch on a value, but they have fundamentally different semantics. Choosing the wrong one introduces bugs that are difficult to spot.
switch uses loose comparison (==) — the same type-juggling rules as if. switch (0) matches case "foo" because 0 == "foo" is true in PHP (string coerced to 0). switch also supports fall-through: execution continues into subsequent cases unless you explicitly break. This is occasionally useful but usually a bug.
match (PHP 8.0) uses strict comparison (===) — no type coercion, no fall-through. match is also an expression (returns a value), and it throws \UnhandledMatchError if no arm matches and there's no default arm. Multiple match values can share an arm: match($x) { 1, 2 => 'low', ... }.
Exhaustiveness: switch silently does nothing if no case matches (falls through to after the switch). match throws an exception — forcing you to handle every case or add default. This makes match safer for dispatch logic.
Performance: Both use hash-based jump tables internally for integer/string values — effectively O(1). The practical difference is in correctness, not speed.
Code Example
<?php
declare(strict_types=1);
// switch — loose comparison (dangerous)
$value = 0;
switch ($value) {
case "hello": // 0 == "hello" is TRUE due to type coercion!
echo "This runs unexpectedly!\n";
break;
case 0:
echo "Zero\n";
break;
}
// Fall-through (intentional)
$day = 'Saturday';
switch ($day) {
case 'Saturday':
case 'Sunday':
echo "Weekend\n"; // both days fall through to here
break;
default:
echo "Weekday\n";
}
// match — strict comparison, no fall-through, expression
$status = 1;
$label = match($status) {
0 => 'inactive',
1 => 'active',
2 => 'suspended',
default => 'unknown',
};
echo $label; // "active"
// match with multiple values per arm
$lang = 'en';
$greeting = match($lang) {
'en', 'en-US', 'en-GB' => 'Hello',
'fr', 'fr-FR' => 'Bonjour',
'de' => 'Hallo',
'ro' => 'Bună',
default => 'Hi',
};
// match throws on unhandled value
$code = 999;
try {
$text = match($code) {
200 => 'OK',
404 => 'Not Found',
500 => 'Server Error',
// 999 not handled, no default → throws
};
} catch (\UnhandledMatchError $e) {
echo "No match for code $code\n";
}
// The string "0" gotcha in switch
switch ("0") {
case false: echo "Matches false!\n"; break; // switch("0") == false → TRUE
case "0": echo "Matches string zero\n"; break;
}
// match("0") { false => ..., "0" => ... } would correctly match "0"