Enums are final, cannot extend anything and cannot be extended, which removes a set of designs that class constants had allowed.
interface HasLabel
{
public function label(): string;
}
enum OrderStatus: string implements HasLabel
{
case Pending = 'pending';
public function label(): string
{
return match ($this) {
self::Pending => __('Awaiting payment'),
};
}
}
// and what is not allowed:
// enum X extends Y — no inheritance, ever
// enum X { public $foo; } — no state
// new OrderStatus() — not instantiable
Implementing an interface is what makes an enum usable as a polymorphic type, and it is the escape hatch for everything inheritance would have done. The prohibition on properties is the constraint people hit first: an enum case is a singleton and giving it mutable state would make two references to the same case disagree, so the language forbids it outright rather than trusting anybody.