Hi,

I'd like to propose an improvement to backed enumerations introduced in PHP 8.1.
When using enums, it's very common to get all values using the following 
boilerplate:
$enumValues = array_map(
    fn (\BackedEnum $case) => $case->value,
    ExampleEnum::cases()
);

The primary use case is when an enum is used in a "set" (array of values).
For example, a user inputs a subset of available values.
The input may be optional defaulting to all values if omitted.
For example, an array option of a CLI tool:
$inputValues = $input->getOption('enum') ?: $enumValues

The secondary use case is for informational purposes.
For example, the CLI tool may list all available values of an enum option in 
--help.
The list of values can also be used to produce informative error messages:
$output->writeln("Option is invalid, allowed values: " . implode(', ', 
$enumValues))

The last use case is input validation.
Although tryFrom() can be used, having access to all values can come in handy.
For instance, you could immediately get valid and invalid enum values:
$invalidValues = array_diff($inputValues, $enumValues);
The implementation would be more verbose and wasteful otherwise:
$invalidValues = array_filter($inputValues, fn ($value) => 
!ExampleEnum::tryFrom($value));

The proposal is to add the values getter to backed enums:
interface BackedEnum extends UnitEnum
{
    public static values(): array;
}
$enumValues = ExampleEnum::values();

Indeed, it's possible to implement this userland in a trait reused across enums.
However, the implementation in C will be substantially more performant.
For instance, the values() method call can resolve to a constant!

An alternative syntax is a pseudo-constant, for example, ExampleEnum::values.
Unlike the constant, the method would be part of the interface complementing 
cases().
Method cases() itself is not a constant only because it returns instances.
I'm fine with either syntax leaning towards the method for consistency.

Please let me know your thoughts.
With enough support, I'd be happy to submit an RFC and implement it myself.
Some guidance on the performance optimization aspect may be necessary though.
I'm still missing the karma necessary to create RFCs in the wiki.

Regards,
Sergii Shymko

Reply via email to