Cách sửa lỗi PHP Fatal error: Uncaught UnhandledMatchError: Unhandled match case

beginner🐘 PHP2026-07-26| PHP 8.0+ (Linux, macOS, hoặc Windows)

Error Message

PHP Fatal error: Uncaught UnhandledMatchError: Unhandled match case
#php#php8#xu-ly-loi#bieu-thuc-match#backend

Cách khắc phục nhanh

Bạn gặp lỗi này vì biểu thức match của bạn gặp phải một giá trị chưa được lập trình để xử lý. Không giống như câu lệnh switch (vốn âm thầm bỏ qua các trường hợp thiếu), biểu thức match bắt buộc phải đầy đủ. Nó yêu cầu một kết quả cho mọi đầu vào có thể xảy ra.

Giải pháp nhanh nhất là thêm một nhánh default vào cuối khối mã:

$result = match ($status) {
    'active'   => 'Người dùng đang trực tuyến',
    'inactive' => 'Người dùng đang ngoại tuyến',
    default    => 'Trạng thái không xác định', // Nhánh an toàn
};

Tại sao lỗi này xảy ra

PHP 8.0 đã giới thiệu match như một sự thay thế hiện đại và nghiêm ngặt hơn cho switch. Nó không chỉ so sánh các giá trị; nó mong đợi sự chắc chắn. Nếu giá trị truyền vào match() không tồn tại trong danh sách bạn đã định nghĩa, PHP sẽ ném ra lỗi UnhandledMatchError và dừng thực thi.

Lỗi này thường bắt nguồn từ hai vấn đề:

- **Thiếu Logic:** Mã của bạn nhận được một giá trị mới (như trạng thái 'pending') mà bạn chưa thêm vào các nhánh của match.
- **Sai lệch kiểu dữ liệu:** Biểu thức `match` sử dụng kiểm tra định danh nghiêm ngặt (`===`). Một số nguyên `200` sẽ không khớp với một chuỗi `"200"`.

Dưới đây là một ví dụ điển hình về lỗi do mã HTTP không được xử lý:

$httpStatus = 404;

$message = match ($httpStatus) {
    200 => "Thành công",
    500 => "Lỗi máy chủ",
};
// Kết quả: Fatal error: Uncaught UnhandledMatchError: Unhandled match case 404

Giải pháp 1: Sử dụng nhánh dự phòng (Fallback)

Thêm một trường hợp default là cách đáng tin cậy nhất để ngăn chặn lỗi. Nó đóng vai trò là điểm dừng cho bất kỳ đầu vào không mong đợi nào. Hãy sử dụng cách này khi bạn muốn ứng dụng tiếp tục chạy ngay cả khi gặp dữ liệu mà bạn không lường trước được.

$role = 'manager';

$permission = match ($role) {
    'admin'  => 'quyền_truy_cập_toàn_diện',
    'editor' => 'chỉnh_sửa_nội_dung',
    default  => 'chỉ_đọc', // Xử lý an toàn cho 'manager', 'guest', hoặc null
};

Giải pháp 2: Bắt buộc xử lý kiểu dữ liệu nghiêm ngặt

match phân biệt kiểu dữ liệu, dữ liệu đến từ $_GET, $_POST hoặc cơ sở dữ liệu thường gây ra vấn đề vì các nguồn đó thường trả về chuỗi. Nếu bạn mong đợi một số nguyên, hãy ép kiểu biến trước khi đưa vào match. Điều này ngăn việc chuỗi "1" bị lỗi khi so sánh với số nguyên 1.

$userId = "101"; // Một chuỗi từ tham số URL

$group = match ((int)$userId) {
    101 => "Nhóm Admin",
    102 => "Nhóm Nhân viên",
    default => "Người dùng thông thường",
};

Giải pháp 3: Khôi phục bằng Try-Catch

Trong một số trường hợp hiếm hoi, bạn có thể muốn xử lý một trường hợp bị thiếu như một sự kiện có thể khôi phục thay vì một lỗi logic. Bạn có thể bao bọc biểu thức trong khối try-catch để ghi nhật ký lỗi mà không làm hỏng toàn bộ quá trình tải trang.

try {
    $color = match ($input) {
        'red'  => '#FF0000',
        'blue' => '#0000FF',
    };
} catch (\UnhandledMatchError $e) {
    $color = '#FFFFFF'; // Mặc định là màu trắng
    error_log("Cảnh báo: Người dùng cung cấp màu không được hỗ trợ: " . $input);
}

Giải pháp 4: Cách tiếp cận tốt nhất (PHP 8.1+ Enums)

Nếu bạn đang sử dụng PHP 8.1 trở lên, Enum là tiêu chuẩn vàng. Bằng cách sử dụng Enum làm kiểu đầu vào, bạn giới hạn các giá trị có thể có ở cấp độ ngôn ngữ. Các IDE hiện đại và công cụ phân tích tĩnh như PHPStan thậm chí sẽ báo đỏ mã của bạn nếu bạn quên xử lý một trong các trường hợp của Enum.

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

function getStatusMessage(UserStatus $status): string {
    return match ($status) {
        UserStatus::Active  => 'Chào mừng bạn trở lại!',
        UserStatus::Banned  => 'Truy cập bị từ chối.',
        UserStatus::Deleted => 'Tài khoản không còn tồn tại.',
        // Không cần default vì tất cả các trường hợp Enum đã được bao phủ
    };
}

Xác minh bản sửa lỗi

Kiểm tra logic của bạn bằng cách truyền một giá trị không hợp lệ qua khối match. Bạn có thể sử dụng một tập lệnh CLI đơn giản để xác nhận nhánh default bắt lỗi đúng như mong đợi.

<?php
// test_match.php
function checkMatch($val) {
    return match ($val) {
        1 => "Tìm thấy số một",
        default => "Bắt được giá trị ngoài dự kiến: " . $val,
    };
}

echo checkMatch(1) . PHP_EOL;  // Đầu ra: Tìm thấy số một
echo checkMatch(999) . PHP_EOL; // Đầu ra: Bắt được giá trị ngoài dự kiến: 999

Chạy lệnh php test_match.php trong terminal của bạn. Nếu tập lệnh in ra thông báo "Bắt được" thay vì ném ra lỗi Fatal Error, bản sửa lỗi của bạn đã ổn.

Các điểm mấu chốt

Chuyển từ switch sang match đòi hỏi sự thay đổi tư duy về tính nghiêm ngặt:

- **Switch:** Sử dụng so sánh lỏng lẻo (`==`) và bỏ qua các trường hợp bị thiếu.
- **Match:** Sử dụng định danh nghiêm ngặt (`===`) và gây lỗi (crash) khi thiếu các trường hợp.

Related Error Notes