пн, 10 нояб. 2025 г. в 08:44, Mikhail Savin <[email protected]>:

> Hi internals,
>
> I've created an RFC to add a native values() method to BackedEnum:
>
> https://wiki.php.net/rfc/add_values_method_to_backed_enum
>
> == Summary ==
>
> The RFC proposes adding BackedEnum::values() that returns an indexed array
> of all backing values. The implementation uses conditional registration -
> the native method is only added when the enum doesn't already define
> values(), ensuring ZERO backward compatibility breaks.
>
> Key points:
>   * Native values() added automatically to new enums
>   * Existing enums with custom values() continue working unchanged
>   * Trait-based implementations are respected
>   * Libraries can maintain their implementation for older PHP versions
>   * Solves boilerplate problem (3,860+ implementations, ~24k-44k real
> usage)
>
> Common use cases:
>   * Database migrations: $table->enum('status', Status::values())
>   * Form validation: in_array($input, Status::values())
>   * API responses: ['allowed_values' => Status::values()]
>
> == Implementation ==
>
> Working implementation with conditional registration:
> https://github.com/php/php-src/pull/20398
>
> The engine checks if values() exists before registering the native version:
>   - User-defined values() present? Use it.
>   - No user-defined values()? Add native implementation.
>
> == No BC Breaks ==
>
> This approach ensures:
>   * Existing code works unchanged (no migration needed)
>   * Immediate benefit for new code (automatic values())
>   * Gradual adoption possible (libraries can migrate at their pace)
>
> Trade-off: Makes values() the only overridable enum method (unlike
> cases/from/tryFrom). The RFC documents this as a pragmatic choice -
> solving real problems without forced migrations.
>
> == Questions ==
>
> 1. Is the conditional approach technically sound?
> 2. Is the API consistency trade-off acceptable given the zero BC breaks?
> 3. Any concerns with the implementation approach?
> 4. Should I implement some steps from "Future scope" of the rfc now?
>
> Discussion period: 2 weeks minimum before voting.
>
> Looking forward to your feedback!
>
> Best regards,
> Savin Mikhail
>

Hi, Mikhail!

Thank you for the RFC.

Consider this code if this RFC is accepted:

enum EnumWithUserDefinedValuesMethod: string
{
    case X = 'x';

    public static function values(): string
    {
        return 'values';
    }
}

function getBackedEnumValues(BackedEnum $enum): array
{
    return $enum::values();
}

getBackedEnumValues(EnumWithUserDefinedValuesMethod::X);


This code will suddenly break, because inside getBackedEnumValues I can
safely assume that BackedEnum::values() returns an array, since it's a part
of the interface contract.

However, EnumWithUserDefinedValuesMethod breaks the Liskov Substitution
Principle by defining a method with a non-compatible return type and gives
a runtime error.

What you've basically suggested is to ignore the LSP. This is not a good
idea.

--
Best regards, Valentin

Reply via email to