PHP 8.0 — Match expression
Concept
The match expression was covered in control flow (php-05-003). This lesson focuses on PHP 8.0's match in the context of PHP version evolution — what it replaces, why it was added, and its interaction with other PHP 8 features.
match was the direct response to switch being too permissive (loose comparison, fall-through) for modern PHP's goal of correctness and explicitness. It's part of PHP 8.0's broader theme of making common patterns safer: match vs switch, str_contains vs strpos !== false, nullsafe ?-> vs manual null checks.
match with enums (PHP 8.1 synergy): The match expression is the natural companion for backed enums. A match on an enum case is exhaustive and strict — if you add a new enum case, static analysis tools (PHPStan, Psalm) will detect any match expressions missing that case.
match(true) pattern: When you need range-based dispatch (conditions are boolean expressions), match(true) evaluates each arm as true === condition. It's a clean alternative to if/elseif chains for multi-branch logic that returns a value.
Nested match for 2D dispatch: Match expressions can be nested to handle two-dimensional decision tables cleanly.
Code Example
<?php
declare(strict_types=1);
// match with enum — exhaustive dispatch
enum OrderStatus
{
case Pending;
case Processing;
case Shipped;
case Delivered;
case Cancelled;
}
function statusColor(OrderStatus $status): string
{
return match($status) {
OrderStatus::Pending => '#FFA500',
OrderStatus::Processing => '#0000FF',
OrderStatus::Shipped => '#800080',
OrderStatus::Delivered => '#008000',
OrderStatus::Cancelled => '#FF0000',
// No default — PHPStan detects missing cases
};
}
// match(true) — range dispatch
function discountTier(int $totalSpent): string
{
return match(true) {
$totalSpent >= 10_000 => 'Platinum',
$totalSpent >= 5_000 => 'Gold',
$totalSpent >= 1_000 => 'Silver',
$totalSpent >= 100 => 'Bronze',
default => 'Standard',
};
}
echo discountTier(7500); // 'Gold'
// match with no-argument as value expression
function processRequest(string $method, string $path): string
{
return match($method) {
'GET' => match(true) {
str_starts_with($path, '/api/') => 'JSON response',
str_starts_with($path, '/admin/') => 'Admin view',
default => 'Public view',
},
'POST' => 'Handle form submission',
'DELETE' => 'Delete resource',
default => throw new \RuntimeException("Unsupported method: $method"),
};
}
// match in array operations
$codes = [200, 404, 500, 301, 422];
$types = array_map(fn($code) => match(true) {
$code >= 500 => 'server-error',
$code >= 400 => 'client-error',
$code >= 300 => 'redirect',
$code >= 200 => 'success',
default => 'info',
}, $codes);