An enum with an interface, and the match I stopped writing

The same match on an enum, in four places, each returning a different aspect of the same thing.

interface HasLabel { public function label(): string; }

enum Status: string implements HasLabel
{
    case Pending = 'pending';
    case Paid    = 'paid';

    public function label(): string
    {
        return match ($this) {
            self::Pending => 'Awaiting payment',
            self::Paid    => 'Paid',
        };
    }

    public function isTerminal(): bool { /* ... */ }
}

Moving the match onto the enum means adding a case produces a compile-time incomplete-match error in one place rather than a silent fallthrough in four. The counter-argument is real: presentation strings on a domain enum is a layering violation, and the honest answer is that isTerminal() belongs there and label() probably belongs in a presenter. We kept both and wrote down why, which is the part that matters.