match

match 式は、値の一致をチェックした結果に基づいて評価結果を分岐します。 switch 文と似ていますが、 match 式は複数の候補と比較される制約式を持ちます。 switch 文とは異なり、 三項演算子のように値を評価します。 switch 文とは異なり、 弱い比較(==)ではなく、 型と値の一致チェック(===) に基づいて行われます。 match 式は PHP 8.0.0 以降で利用可能です。

例1 match 式の構造

<?php
$return_value = match (制約式) {
    単一の条件式 => 返却式,
    条件式1, 条件式2 => 返却式,
};
?>

例2 基本式な match 式の使い方

<?php
$food = 'cake';

$return_value = match ($food) {
    'apple' => 'This food is an apple',
    'bar' => 'This food is a bar',
    'cake' => 'This food is a cake',
};

var_dump($return_value);
?>

上の例の出力は以下となります。

string(19) "This food is a cake"

例3 比較演算子と match 式を一緒に使う例

<?php
$age = 18;

$output = match (true) {
    $age < 2 => "Baby",
    $age < 13 => "Child",
    $age <= 19 => "Teenager",
    $age > 19 => "Young adult",
    $age >= 40 => "Old adult"
};

var_dump($output);
?>

上の例の出力は以下となります。

string(8) "Teenager"

注意: match 式の結果は、必ずしも使う必要はありません。

注意: match 式は、必ずセミコロン ; で終わらなければなりません。

match 式は、 switch 文と似ていますが、いくつかの違いがあります:

  • match 式の比較は、 switch 文が行う弱い比較ではなく、 厳密に値を比較(===) します。
  • match 式は値を返します。
  • match 式の分岐は、 switch 文のように後の分岐に抜けたりはしません。
  • match 式は、全ての場合を網羅していなければいけません。

switch 文のように、 match 式はマッチさせる分岐をひとつひとつ実行します。 はじめは、コードは何も実行されません。 以前のすべての条件式が、制約式とマッチしなかった場合に条件式が実行されます。 条件式に一致する式が評価された場合に、返却式が評価されます。 たとえば、以下のようになります:

<?php
$result = match ($x) {
    foo() => ...,
    $this->bar() => ..., // foo() === $x であれば $this->bar() は呼び出されません。
    $this->baz => beep(), // $x === $this->baz でなければ beep() は呼び出されません。
    // などなど
};
?>

match 式の分岐は、複数の式をカンマ区切りで含めても構いません。 これは論理ORであり、複数の分岐の右辺を同じにする場合の短縮記法です。

<?php
$result = match ($x) {
    // この分岐は:
    $a, $b, $c => 5,
    // 以下の3つの分岐と等しい:
    $a => 5,
    $b => 5,
    $c => 5,
};
?>

default パターンという特別な場合があります。 このパターンは前の分岐にマッチしなかったあらゆる場合にマッチします。 たとえば、以下のようになります:

<?php
$expressionResult = match ($condition) {
    1, 2 => foo(),
    3, 4 => bar(),
    default => baz(),
};
?>

注意: 複数の default パターンがあった場合、 E_FATAL_ERROR が発生します。

match 式は、全ての場合を網羅していなければいけません。 制約式がどの分岐でも処理できなかった場合、 UnhandledMatchError がスローされます。

例4 処理されない match 式の例

<?php
$condition = 5;

try {
    match ($condition) {
        1, 2 => foo(),
        3, 4 => bar(),
    };
} catch (\UnhandledMatchError $e) {
    var_dump($e);
}
?>

上の例の出力は以下となります。

object(UnhandledMatchError)#1 (7) {
  ["message":protected]=>
  string(33) "Unhandled match value of type int"
  ["string":"Error":private]=>
  string(0) ""
  ["code":protected]=>
  int(0)
  ["file":protected]=>
  string(9) "/in/ICgGK"
  ["line":protected]=>
  int(6)
  ["trace":"Error":private]=>
  array(0) {
  }
  ["previous":"Error":private]=>
  NULL
}

厳密な一致チェックを行わずに match 式を使う

制約式に true を指定することで、 厳密な一致チェックを行わずに match 式を使うことができます。

例5 整数の範囲に応じてmatch式を分岐させる一般的な使い方

<?php

$age = 23;

$result = match (true) {
    $age >= 65 => 'senior',
    $age >= 25 => 'adult',
    $age >= 18 => 'young adult',
    default => 'kid',
};

var_dump($result);
?>

上の例の出力は以下となります。

string(11) "young adult"

例6 文字列の内容に応じてmatch式を分岐させる一般的な使い方

<?php

$text = 'Bienvenue chez nous';

$result = match (true) {
    str_contains($text, 'Welcome') || str_contains($text, 'Hello') => 'en',
    str_contains($text, 'Bienvenue') || str_contains($text, 'Bonjour') => 'fr',
    // ...
};

var_dump($result);
?>

上の例の出力は以下となります。

string(2) "fr"