Language
日本語
English

Caution

JavaScript is disabled in your browser.
This site uses JavaScript for features such as search.
For the best experience, please enable JavaScript before browsing this site.

PHP Dictionary

  1. Home
  2. PHP Dictionary
  3. match Expression

match Expression

Since: PHP 8.0(2020)

To branch on multiple values and return the result as an expression, the 『match』 expression introduced in PHP 8 is useful. Similar to 『switch』, but it uses strict comparison (===) so no unintended type coercion occurs, and it can return a value directly for concise code.

Syntax

$variable = match (expression) {
	value1 => return_value,
	value2 => return_value,
	value3, value4 => return_value, // multiple values can be grouped with commas
	default => default_return_value,
};

Syntax Parts

SyntaxNotes
match (expression)Specifies the value to match against. Any expression can be used: variables, function return values, calculations, etc.
value => return_valueEach branch, called an "arm". When the match expression strictly matches (===) the arm's value, the right side is returned.
value3, value4 => return_valueMultiple values can be listed with commas. The right side is returned when any of the listed values match.
defaultOptional. Specifies the value to return when no arm matches. If omitted and nothing matches, an exception is thrown (see below).

Differences from switch

Aspectswitch statementmatch expression (PHP 8+)
ComparisonLoose comparison (==). Type coercion occurs.Strict comparison (===). No type coercion.
Return valueExecutes statements only; does not return a value.Returns a value as an expression; can be assigned to a variable.
break requiredNormally required at the end of each block.Not required. Each arm is independent.
Fall-throughOccurs when 『break』 is omitted.Does not occur.
Multiple conditionsMultiple 『case』 labels with fall-through.Multiple values in one arm, separated by commas.
No matchIf no 『default』, nothing executes.If no 『default』 and nothing matches, 『UnhandledMatchError』 is thrown.

Exception When No Arm Matches

When a 『match』 expression has no matching arm and no 『default』, an 『UnhandledMatchError』 is thrown. This design allows unexpected values to be caught early as bugs.

PatternBehavior
With defaultWhen no arm matches, the 『default』 value is returned.
No default, match foundThe matched arm's value is returned.
No default, no matchAn 『UnhandledMatchError』 exception is thrown. Unexpected values are detected as bugs.

When unexpected values may be passed, adding 『default』 or catching the exception with 『try / catch』 are available options. For exception handling, see 『try / catch / finally』.

Sample Code

match_basic.php
<?php
// Determining the race of a Dragon Ball character
// Using match expression to assign a value to a variable
$characterName = "Goku";
$race = "Saiyan";

// match returns a value as an expression, so it can be assigned directly
$description = match($race) {
	"Saiyan" => "A warrior race. Capable of transforming into Super Saiyan.",
	"Namekian" => "From Planet Namek. Piccolo can fuse with others.",
	"Android" => "Artificial humans developed by Dr. Gero.",
	default => "Race unknown.",
};

echo $characterName . ": " . $description . "\n";

// Equivalent using switch (same behavior as the match expression above)
switch ($race) {
	case "Saiyan":
		$desc2 = "A warrior race. Capable of transforming into Super Saiyan.";
		break;
	case "Namekian":
		$desc2 = "From Planet Namek. Piccolo can fuse with others.";
		break;
	case "Android":
		$desc2 = "Artificial humans developed by Dr. Gero.";
		break;
	default:
		$desc2 = "Race unknown.";
		break;
}

echo $characterName . " (switch): " . $desc2 . "\n";

Running the code produces the following output:

php match_basic.php
Goku: A warrior race. Capable of transforming into Super Saiyan.
Goku (switch): A warrior race. Capable of transforming into Super Saiyan.
match_multi_conditions.php
<?php
// Grouping multiple values in a single arm using comma separation
// Determining the faction of Dragon Ball characters

$characters = ["Goku", "Vegeta", "Piccolo", "Frieza", "Cell", "Majin Buu"];

foreach ($characters as $name) {
	$faction = match($name) {
		// Multiple values can be grouped with commas (equivalent to switch fall-through)
		"Goku", "Vegeta", "Piccolo" => "Z Warriors",
		"Frieza", "Cell", "Majin Buu" => "Villain",
		default => "Unknown",
	};

	echo $name . ": " . $faction . "\n";
}

Running the code produces the following output:

php match_multi_conditions.php
Goku: Z Warriors
Vegeta: Z Warriors
Piccolo: Z Warriors
Frieza: Villain
Cell: Villain
Majin Buu: Villain
match_strict_comparison.php
<?php
// match uses strict comparison (===)
// Checking the difference from switch's loose comparison

// Managing power level as an integer
$powerLevel = 0; // power level zero (latent ability unreleased)

echo "--- match (strict comparison) ---\n";
$result = match($powerLevel) {
	0 => "Latent ability unreleased (strict match with integer 0)",
	false => "false (type differs, no match)",
	"" => "empty string (type differs, no match)",
	default => "no match",
};
// match uses strict comparison, so integer 0 does not match false or empty string
echo "Result: " . $result . "\n";

echo "\n--- switch (loose comparison) ---\n";
switch ($powerLevel) {
	case false:
		// 0 == false is true, so this executes (unintended match)
		echo "Result: matched false (unintended loose comparison match)\n";
		break;
	case 0:
		echo "Result: matched integer 0\n";
		break;
}

Running the code produces the following output:

php match_strict_comparison.php
--- match (strict comparison) ---
Result: Latent ability unreleased (strict match with integer 0)

--- switch (loose comparison) ---
Result: matched false (unintended loose comparison match)
match_unhandled_error.php
<?php
// Behavior when a match expression without default receives a value matching no arm

$characterName = "Broly";
$transformation = "Legendary Super Saiyan";

// Only expected transformations are listed as arms
// Without default, passing an unlisted value throws an exception
try {
	$powerMultiplier = match($transformation) {
		"Super Saiyan" => 50,
		"Super Saiyan 2" => 100,
		"Super Saiyan 3" => 400,
		"Super Saiyan God" => 1000,
		// "Legendary Super Saiyan" is not in the arms, so an exception is thrown
	};
	echo $characterName . ": multiplier " . $powerMultiplier . "x\n";
} catch (\UnhandledMatchError $e) {
	// Thrown when a match expression without default receives a value that matches no arm
	echo "UnhandledMatchError: transformation \"" . $transformation . "\" is not defined in the arms.\n";
}

// Adding default avoids the exception
$powerMultiplier2 = match($transformation) {
	"Super Saiyan" => 50,
	"Super Saiyan 2" => 100,
	"Super Saiyan 3" => 400,
	"Super Saiyan God" => 1000,
	default => "immeasurable",
};
echo $characterName . ": multiplier " . $powerMultiplier2 . "\n";

Running the code produces the following output:

php match_unhandled_error.php
UnhandledMatchError: transformation "Legendary Super Saiyan" is not defined in the arms.
Broly: multiplier immeasurable
match_true_pattern.php
<?php
// match(true) can handle range comparisons
// Determining a Dragon Ball character's rank from their power level

function getBattleRank(int $power): string
{
	// match(true) evaluates each arm's expression and returns the first that is true
	return match(true) {
		$power >= 1000000 => "Divine Realm",
		$power >= 100000 => "Super Saiyan Class",
		$power >= 10000 => "Elite Warrior Class",
		$power >= 1000 => "Mid-Level Warrior Class",
		default => "Common Warrior Class",
	};
}

$fighters = [
	["name" => "Goku", "power" => 3000000],
	["name" => "Vegeta", "power" => 500000],
	["name" => "Piccolo", "power" => 42000],
	["name" => "Yamcha", "power" => 1480],
	["name" => "Oolong", "power" => 10],
];

foreach ($fighters as $fighter) {
	$rank = getBattleRank($fighter['power']);
	echo $fighter['name'] . " (" . number_format($fighter['power']) . "): " . $rank . "\n";
}

Running the code produces the following output:

php match_true_pattern.php
Goku (3,000,000): Divine Realm
Vegeta (500,000): Super Saiyan Class
Piccolo (42,000): Elite Warrior Class
Yamcha (1,480): Mid-Level Warrior Class
Oolong (10): Common Warrior Class

Common Mistakes

Common Mistake 1: UnhandledMatchError occurs due to missing default

When a 『match』 expression omits 『default』 and a value matching no arm is passed, an 『UnhandledMatchError』 exception is thrown. When unexpected values may be passed, either add 『default』 or catch the exception with 『try / catch』.

ng_no_default.php
<?php
$transformation = "Super Saiyan God"; // not in any arm

// Without default, passing an undefined value throws an exception
$multiplier = match($transformation) {
	"Super Saiyan" => 50,
	"Super Saiyan 2" => 100,
	"Super Saiyan 3" => 400,
};

echo "Multiplier: " . $multiplier . "\n";

Running the code produces the following output:

php ng_no_default.php
Fatal error: Uncaught UnhandledMatchError: Unhandled match case
ok_no_default.php
<?php
$transformation = "Super Saiyan God";

// Add default to handle undefined values
$multiplier = match($transformation) {
	"Super Saiyan" => 50,
	"Super Saiyan 2" => 100,
	"Super Saiyan 3" => 400,
	default => "immeasurable",
};

echo "Multiplier: " . $multiplier . "\n";

Running the code produces the following output:

php ok_no_default.php
Multiplier: immeasurable

Common Mistake 2: Misplaced semicolon or missing comma between arms

Because 『match』 is an expression, it must be used as part of an assignment or another expression. The semicolon goes outside the closing brace of the match block. Each arm must be followed by a comma, including the last arm.

ng_semicolon.php
<?php
$rank = "Inspector";

// match is an expression, not a statement like switch
// Missing comma between arms causes a parse error
$description = match($rank) {
	"Inspector" => "Public Safety Bureau Inspector"
	// Missing comma — this causes a parse error
	"Enforcer" => "Registered latent criminal"
};

Running the code produces the following output:

php ng_semicolon.php
Parse error: syntax error, unexpected double-quoted string "Enforcer"
ok_semicolon.php
<?php
$rank = "Inspector";

// Each arm ends with a comma (including the last arm)
$description = match($rank) {
	"Inspector" => "Public Safety Bureau Inspector",
	"Enforcer" => "Registered latent criminal",
	default => "Civilian",
};

echo $description . "\n";

Running the code produces the following output:

php ok_semicolon.php
Public Safety Bureau Inspector

Common Mistake 3: Trying to use match like a switch statement with multi-statement blocks

Each arm of a 『match』 expression returns a single expression. It is not designed for executing multiple statements (e.g., echoing and then updating a variable). When multiple operations are needed, use 『switch』 or 『if』.

ng_multi_statement.php
<?php
$power = 9000;

// Each arm can only contain a single expression
// Trying to write a block with multiple statements causes a parse error
$result = match(true) {
	$power >= 9000 => {
		echo "Extremely high power level\n"; // Parse error: block syntax is not allowed
		"Elite",
	},
	default => "Common",
};

Running the code produces the following output:

php ng_multi_statement.php
Parse error: syntax error, unexpected token "{"
ok_multi_statement.php
<?php
$power = 9000;

// Use if or switch when multiple operations are needed
if ($power >= 9000) {
	echo "Extremely high power level\n";
	$rank = "Elite";
} else {
	$rank = "Common";
}

echo "Rank: " . $rank . "\n";

Running the code produces the following output:

php ok_multi_statement.php
Extremely high power level
Rank: Elite

Notes

The 『match』 expression was introduced in PHP 8 as a conditional branching syntax. Its key differences from 『switch』 are that it returns a value as an expression, and it uses strict comparison (===). Strict comparison prevents unintended matches caused by type coercion, such as integer 『0』 matching a string or 『false』. For details on type coercion, see 『Type Casting』.

Each arm can group multiple values with comma separation, allowing patterns previously handled by intentional fall-through in 『switch』 to be expressed more safely. Because 『break』 is not needed, bugs from forgetting it are also avoided. When 『default』 is omitted, a value that matches no arm causes an 『UnhandledMatchError』 exception. Omitting 『default』 is appropriate when you want unexpected values to be detected early as bugs; otherwise, adding 『default』 is the safer choice.

For range comparisons, 『match(true)』 can be used to evaluate each arm's condition expression in order. However, when conditions are complex or involve multiple variables, 『if / elseif / else』 may be more readable. For a detailed comparison with 『switch』, see 『switch statement』.

If you find any errors or copyright issues, please .