0

PHP 8.0 — Match expression

Intermediate5 min read·php-09-004

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
<?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);