Enums in Practice

Enums in match Arms, Arrays and Database Columns

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):

Mapping the orders.status ENUM column to OrderStatus, with an exhaustive matchPHP
<?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.