match (Subsection 4.3.6) compares with ===, so it pairs naturally with cases. Leave out default and a forgotten case throws UnhandledMatchError instead of falling through. A case cannot be an array key ("Cannot access offset of type OrderStatus on array"): key by ->value, or use SplObjectStorage. The column holds the backing value: convert with from() as each row arrives, so a bad value fails at the edge, and bind ->value when writing. This reads the MySQL shop database (PDO is Databases with PDO):
<?php
enum OrderStatus: string {
case Pending = 'pending'; case Paid = 'paid';
case Shipped = 'shipped'; case Cancelled = 'cancelled';
}
function badge(OrderStatus $s): string {
return match ($s) { // no default: a forgotten case fails loudly
OrderStatus::Pending, OrderStatus::Paid => 'open',
OrderStatus::Shipped => 'done',
};
}
$pdo = new PDO('mysql:host=localhost;dbname=shop;charset=utf8mb4', 'shop_app', 'secret');
$st = $pdo->prepare('SELECT id, status FROM orders WHERE status <> ? ORDER BY id DESC LIMIT 3');
$st->execute([OrderStatus::Shipped->value]); // case -> column string
foreach ($st as $row) {
$status = OrderStatus::from($row['status']); // column string -> case
printf("#%d %-8s %s\n", $row['id'], $status->name, badge($status));
}
try { badge(OrderStatus::Cancelled); }
catch (UnhandledMatchError $e) { echo $e->getMessage(), "\n"; }Output
#9 Paid open #8 Pending open #7 Paid open Unhandled match case of type OrderStatus
When a new status arrives, change the ENUM column (MySQL) and the PHP enum in the same release; every match without default then points you at a place that needs a new arm.