PHP Fatal error: Uncaught UnhandledMatchError: Unhandled match case の修正方法

beginner🐘 PHP2026-07-26| PHP 8.0以降 (Linux, macOS, または Windows)

Error Message

PHP Fatal error: Uncaught UnhandledMatchError: Unhandled match case
#php#php8#エラーハンドリング#match式#バックエンド

クイック修正

このエラーは、match式がプログラムで処理されていない値に遭遇したために発生します。該当するケースがない場合に暗黙的に無視される switch 文とは異なり、match 式は**網羅的(exhaustive)**である必要があります。つまり、考えられるすべての入力に対して結果を用意しなければなりません。

最も手っ取り早い解決策は、ブロックの最後に default アームを追加することです。

$result = match ($status) {
    'active'   => 'ユーザーはオンラインです',
    'inactive' => 'ユーザーはオフラインです',
    default    => 'ステータス不明', // セーフティネット
};

エラーが発生する理由

PHP 8.0 では、switch に代わるより厳密でモダンな選択肢として match が導入されました。単に値を比較するだけでなく、確実性を求めます。match() に渡された値が定義されたリストに存在しない場合、PHP は UnhandledMatchError をスローし、実行を停止します。

このクラッシュは通常、次の2つの問題に起因します。

- **ロジックの不足:** `match` アームにまだ追加していない新しい値('pending' ステータスなど)をコードが受け取った。
- **型の不一致:** `match` 式は厳密な型チェック (`===`) を使用します。整数型の `200` は、文字列型の `"200"` とは一致しません。

以下は、処理されていないHTTPコードによって発生するクラッシュの典型的な例です。

$httpStatus = 404;

$message = match ($httpStatus) {
    200 => "成功",
    500 => "サーバーエラー",
};
// 結果: Fatal error: Uncaught UnhandledMatchError: Unhandled match case 404

解決策1:フォールバックアームを使用する

default ケースを追加することは、クラッシュを防ぐ最も信頼性の高い方法です。これは、予期しない入力に対するキャッチオール(すべてを拾う仕組み)として機能します。予期しないデータに遭遇してもアプリケーションの実行を継続させたい場合に使用します。

$role = 'manager';

$permission = match ($role) {
    'admin'  => 'フルアクセス',
    'editor' => 'コンテンツ編集',
    default  => '閲覧のみ', // 'manager'、'guest'、または null を安全に処理
};

解決策2:厳密な型処理を強制する

match は型に敏感であるため、$_GET$_POST、またはデータベースからのデータは、通常文字列を返すため問題を引き起こすことがよくあります。整数を期待する場合は、マッチングを行う前に変数をキャストしてください。これにより、"1" が整数型の 1 と一致せずにエラーになるのを防げます。

$userId = "101"; // URLパラメータからの文字列

$group = match ((int)$userId) {
    101 => "管理者グループ",
    102 => "スタッフグループ",
    default => "一般ユーザー",
};

解決策3:Try-Catchでリカバリする

まれに、ケースの欠落をロジックエラーではなく、回復可能なイベントとして扱いたい場合があります。その場合、式を try-catch ブロックで囲むことで、ページ全体の読み込みを停止させることなく問題をログに記録できます。

try {
    $color = match ($input) {
        'red'  => '#FF0000',
        'blue' => '#0000FF',
    };
} catch (\UnhandledMatchError $e) {
    $color = '#FFFFFF'; // デフォルトは白
    error_log("警告: ユーザーがサポートされていない色を指定しました: " . $input);
}

解決策4:ベストプラクティス(PHP 8.1以降のEnum)

PHP 8.1 以降を使用している場合、Enum(列挙型)が最も推奨される方法です。Enum を入力型として使用することで、言語レベルで可能な値を制限できます。モダンなIDEや PHPStan などの静的解析ツールは、Enum のケースのいずれかを処理し忘れている場合に、コードを赤く強調表示して教えてくれます。

enum UserStatus {
    case Active;
    case Banned;
    case Deleted;
}

function getStatusMessage(UserStatus $status): string {
    return match ($status) {
        UserStatus::Active  => 'おかえりなさい!',
        UserStatus::Banned  => 'アクセスが拒否されました。',
        UserStatus::Deleted => 'アカウントはもう存在しません。',
        // すべてのEnumケースが網羅されているため、defaultは不要
    };
}

修正の確認

match ブロックに無効な値を渡して、ロジックをテストしてください。シンプルな CLI スクリプトを使用して、期待通りに default アームがエラーをキャッチすることを確認できます。

<?php
// test_match.php
function checkMatch($val) {
    return match ($val) {
        1 => "1が見つかりました",
        default => "予期しない値をキャッチしました: " . $val,
    };
}

echo checkMatch(1) . PHP_EOL;  // 出力: 1が見つかりました
echo checkMatch(999) . PHP_EOL; // 出力: 予期しない値をキャッチしました: 999

ターミナルで php test_match.php を実行します。スクリプトが Fatal Error をスローせずに「予期しない値をキャッチしました」というメッセージを表示すれば、修正は完璧です。

重要なポイント

switch から match に切り替えるには、厳密さに関する考え方を変える必要があります。

- **Switch:** 緩やかな比較 (`==`) を使用し、一致するケースがない場合は無視する。
- **Match:** 厳密な比較 (`===`) を使用し、一致するケースがない場合はクラッシュする。

Related Error Notes