LearnContact
Lesson 2318 min read

Match Expression

Learn the PHP 8 match expression, how it improves on switch with strict comparisons and no fall-through, and how to match multiple values in one arm.

Introduction

The previous lesson covered switch, PHP's classic tool for comparing a value against many possibilities. PHP 8 introduced a modern alternative called match, designed specifically to fix the sharp edges of switch: accidental fall-through, loose comparison, and the need to manually assign a result inside every branch.

In this lesson you will learn match's syntax, how it behaves differently from switch, how to match several values in a single arm, and what happens when nothing matches.

What You Will Learn
  • How the match expression is written and how it returns a value directly.
  • Why match uses strict (===) comparison and never falls through.
  • How to match multiple values in a single arm using commas.
  • What UnhandledMatchError is and when it is thrown.
  • How an equivalent switch and match compare side by side.

What is match?

match is an expression, not a statement — meaning it directly produces (and can be assigned or returned as) a value, rather than requiring you to echo or assign inside each branch. It was added in PHP 8.0 as a more predictable, more concise way to compare a single value against several possibilities.

Strict Comparison

match compares using === by default, avoiding surprising type-juggling bugs.

Returns a Value

match is an expression — you can assign its result directly to a variable.

No Fall-Through

Each arm is isolated; there is no break to remember and no accidental fall-through.

Throws on No Match

If nothing matches and there is no default, PHP throws UnhandledMatchError.

Basic Syntax

A match expression takes a subject value, compares it against a list of arms (condition => result), and evaluates to the result of the first matching arm. A default arm can be written as an underscore, _, to catch every other case.

match-basic.php
<?php
$statusCode = 404;

$message = match ($statusCode) {
    200 => "OK",
    301, 302 => "Redirect",
    404 => "Not Found",
    500 => "Server Error",
    default => "Unknown Status",
};

echo $message;
Output
Not Found

Notice that each arm ends with a comma, not a break, and the whole expression can be assigned straight to $message.

match vs switch

match and switch solve a similar problem, but they behave quite differently under the hood.

switch (classic)

  • Compares using loose == by default
  • Falls through to the next case without break
  • A statement — you assign or echo manually inside each case
  • No error if nothing matches and there is no default

match (PHP 8+)

  • Compares using strict === by default
  • Never falls through — each arm is independent
  • An expression — it returns a value directly
  • Throws UnhandledMatchError if nothing matches and there is no default
Why Strict Comparison Matters

Because match uses ===, matching the string "1" against the integer 1 will not succeed, unlike switch, which would treat them as equal under loose comparison. This removes a whole category of subtle type-juggling bugs.

Matching Multiple Values

Just like grouped switch cases, a single match arm can handle multiple values by separating them with commas. The arm runs if the subject strictly equals any one of the listed values.

match-multiple.php
<?php
$day = "Sat";

$type = match ($day) {
    "Mon", "Tue", "Wed", "Thu", "Fri" => "Weekday",
    "Sat", "Sun" => "Weekend",
};

echo $type;
Output
Weekend

Unhandled Values

If none of the arms match and there is no default (written as _), PHP throws an UnhandledMatchError instead of silently doing nothing. This is a deliberate safety feature — it surfaces missing cases immediately instead of letting a bug hide.

match-unhandled.php
<?php
$grade = "Z";

try {
    $result = match ($grade) {
        "A" => "Excellent",
        "B" => "Good",
    };
} catch (\UnhandledMatchError $e) {
    $result = "Error: " . $e->getMessage();
}

echo $result;
Output
Error: Unhandled match case 'Z'
Always Consider a Default

Unless you are certain every possible value is covered, add a default arm (_) to avoid an uncaught UnhandledMatchError crashing your script.

Side-by-Side Example

Here is the same logic — converting a numeric grade into a letter — written first as a switch statement, then as an equivalent match expression, so you can compare the two styles directly.

switch-version.php
<?php
$score = 85;
$letter = "";

switch (true) {
    case $score >= 90:
        $letter = "A";
        break;
    case $score >= 80:
        $letter = "B";
        break;
    case $score >= 70:
        $letter = "C";
        break;
    default:
        $letter = "F";
        break;
}

echo $letter;
Output (switch version)
B
match-version.php
<?php
$score = 85;

$letter = match (true) {
    $score >= 90 => "A",
    $score >= 80 => "B",
    $score >= 70 => "C",
    default => "F",
};

echo $letter;
Output (match version)
B

Both produce the same result, but the match version needs no break statements, no pre-declared $letter variable, and reads as a single direct assignment. Using match (true) with boolean arms is a common pattern for range-style comparisons like this one.

Common Mistakes

Avoid These Mistakes
  • Expecting match to use loose comparison like switch — it uses strict === by default.
  • Forgetting a default arm and letting an UnhandledMatchError crash the script.
  • Adding break inside a match arm — it is unnecessary and a syntax error.
  • Using match for side effects (like echoing in every arm) instead of returning a value, which defeats its purpose.

Best Practices

  • Prefer match over switch in PHP 8+ code for value comparisons.
  • Use match(true) with boolean expressions for range-style comparisons.
  • Always include a default arm unless you intentionally want UnhandledMatchError.
  • Assign the result of match directly to a variable rather than repeating logic in every arm.

Frequently Asked Questions

Can match replace every switch statement?

In most cases yes, especially for simple value comparisons. switch can still be useful when you need to fall through intentionally or run multiple statements per case without producing a single value.

Does match need a default arm?

Not strictly, but without one, an unmatched value throws UnhandledMatchError. It is good practice to include a default unless you have deliberately covered every case.

Which PHP version added match?

match was introduced in PHP 8.0.

Can a match arm run multiple statements?

A match arm evaluates a single expression. For multiple statements, call a function from the arm, or use switch instead.

Key Takeaways

  • match is a PHP 8 expression that returns a value directly.
  • It compares using strict === by default, unlike switch's loose ==.
  • There is no fall-through and no break needed between arms.
  • Multiple values can share one arm using a comma-separated list.
  • An unmatched value with no default throws UnhandledMatchError.

Summary

The match expression is PHP 8's modern, safer alternative to switch. It compares strictly, never falls through, and returns a value directly, making your code shorter and less error-prone for value-comparison logic.

Lesson 23 Completed
  • You understand how match differs from switch.
  • You can match multiple values in a single arm.
  • You know what UnhandledMatchError means and how to guard against it.
  • You are ready to move on to loops.
Next Lesson →

Loops