Enums are 8.1, so a set of allowed values in 2020 is class constants with a validating constructor — and the gaps are worth naming rather than discovering.
final class OrderStatus
{
public const PENDING = 'pending';
public const PAID = 'paid';
private const ALL = [self::PENDING, self::PAID];
private string $value;
public function __construct(string $value)
{
if (! in_array($value, self::ALL, true)) {
throw new InvalidArgumentException($value);
}
$this->value = $value;
}
}
Three things this cannot do. It cannot be exhaustively checked, so a match over the constants has no compiler telling you when one is missed. It cannot be used as a type hint that guarantees validity — the constructor can be bypassed by anything that unserialises. And two instances of the same value are not identical, so === fails and every comparison needs a method. All three go away in 8.1, which is worth knowing when deciding how much to build now.