The PHP match expression, introduced in PHP 8, is a modern construct for matching values and returning results. Unlike the switch statement, it is an expression, meaning that match always returns a value that can be assigned to a variable or returned from a function.
Why it matters:
- Cleaner code: shorter, more readable than
if,elseif, andelsechains andswitch. - Safer: uses strict comparison (===) - no unexpected matches like in
switch. - No fall-through: you don’t need
break;. - Requires completeness: if not all cases are covered, PHP throws an error (unless you add
default).
In practice, match is great for mapping values, formatting statuses, selecting labels, simple routers, and working with enums (PHP 8.1+). Enums are beyond this course, but if you want to go deeper, there is a complete guide to PHP enums on the blog.
A common gotcha: the thing that trips people up most when moving from switch to match is strict comparison with === - match compares with ===, so the string '2' does not match the integer 2. The second gotcha is coverage: if no arm matches and there is no default, PHP throws an UnhandledMatchError instead of quietly doing nothing like switch. Both are intentional - they catch bugs early. For a deeper side-by-side breakdown, see what actually changed between match and switch.
How the PHP match expression works
PHP match vs switch vs if/elseif
-
match vs switch
- match uses strict identity (===), switch defaults to loose (==).
- match is an expression (returns a value), switch is a statement (does not).
- match has no fall-through - each arm ends automatically, no
breakneeded. - match enforces full coverage (or
default), otherwiseUnhandledMatchErroris thrown.
-
match vs if/elseif
- if/elseif is more flexible for complex conditions or ranges.
- match is ideal for simple 1:1 matches (or multiple values to one result).
- You can use the
match (true)trick for ranges (see below).
Basic syntax
- Each arm has the form:
condition => result, - You can group multiple values in one arm, separated by commas.
- The
defaultarm is optional but recommended.
PHP match expression examples
Map a value to text with match
<?php
$day = 3;
$dayName = match ($day) {
1 => 'Monday',
2 => 'Tuesday',
3 => 'Wednesday',
4 => 'Thursday',
5 => 'Friday',
6 => 'Saturday',
7 => 'Sunday',
default => 'Invalid day number',
};
echo $dayName; // Wednesday
Multiple values in one arm
<?php
$status = 201;
$message = match ($status) {
200, 201, 202 => 'Success or accepted',
400, 404 => 'Client error',
500, 502, 503 => 'Server error',
default => 'Unknown status',
};
echo $message; // Success or accepted
match as an expression: assignment and return
<?php
function normalizeRole(string $role): string
{
return match (strtolower($role)) {
'admin' => 'admin',
'owner', 'superuser' => 'admin',
'editor' => 'editor',
'viewer', 'reader' => 'viewer',
default => 'guest',
};
}
$userRole = normalizeRole('SuperUser'); // admin
Ranges with match(true)
<?php
$score = 87;
$grade = match (true) {
$score >= 90 => 'A',
$score >= 80 => 'B',
$score >= 70 => 'C',
$score >= 60 => 'D',
default => 'F',
};
echo $grade; // B
Incomplete matches and UnhandledMatchError
<?php
$day = 8;
try {
$type = match ($day) {
1, 2, 3, 4, 5 => 'weekday',
6, 7 => 'weekend',
// missing default → UnhandledMatchError
};
} catch (UnhandledMatchError $e) {
echo "Match error: " . $e->getMessage();
}
Throwing exceptions inside match arms
<?php
function requireNonEmpty(?string $value): string
{
return match (true) {
$value === null, $value === '' => throw new InvalidArgumentException('Value cannot be empty'),
default => $value,
};
}
echo requireNonEmpty('ok'); // ok
match with enums (PHP 8.1+)
<?php
enum Status: string {
case Draft = 'draft';
case Published = 'published';
case Archived = 'archived';
}
function statusLabel(Status $s): string
{
return match ($s) {
Status::Draft => 'Draft',
Status::Published => 'Published',
Status::Archived => 'Archived',
};
}
echo statusLabel(Status::Published); // Published
Strict equality: '5' vs 5
<?php
$input = '2';
$result = match ($input) {
2 => 'number two', // no match (int vs string)
'2' => 'string two', // this matches
default => 'other',
};
echo $result; // string two
Best Practices and Common Mistakes
Best Practices
- Use match for value mapping (1:1 or grouped values).
- Ensure completeness: add
defaultor cover all values. - Keep return types consistent (e.g., all strings).
- Use match(true) for simple range conditions.
- Combine with enums for maximum safety (forces full coverage).
- Keep arms simple; extract heavy logic into functions.
- Always end arms with commas.
Common Mistakes
- Forgetting
defaultor incomplete coverage → UnhandledMatchError. - Expecting loose comparison (==) like switch → match uses strict ===.
- Mixing return types across arms → may cause TypeError or reduce clarity.
- Putting side effects inside arms → harder to test; better to extract logic.
- Duplicating values in multiple arms → later arms are unreachable.
Summary
- The match expression in PHP 8+ is concise, strict, and safer than switch.
- It’s an expression: always returns a value.
- Uses strict identity (===).
- No fall-through, no
breakneeded. - Enforces full coverage (or
default). - Ideal for mapping, enums, and validation.
Now you know how to use the PHP match expression to write cleaner, safer, and more predictable conditionals.
FAQ
What is the difference between PHP match and switch?
match uses strict comparison (===), is an expression that returns a value, has no fall-through (so no break), and requires every case to be covered or it throws. switch uses loose comparison (==), is a statement that returns nothing, and falls through until it hits a break.
Does the PHP match expression use strict comparison?
Yes. match compares with === (strict identity), so the types must match too - the string '2' will not match the integer 2.
What happens if no arm matches in a PHP match?
If no arm matches and there is no default, PHP throws an UnhandledMatchError. Add a default arm to safely handle every other value.
When was the match expression added to PHP?
The match expression was added in PHP 8.0. Using it with enums requires PHP 8.1 or newer.