пт, 7 нояб. 2025 г. в 07:53, Mikhail Savin <[email protected]>:
> > > пт, 7 нояб. 2025 г. в 07:08, Valentin Udaltsov < > [email protected]>: > >> чт, 6 нояб. 2025 г., 19:30 Larry Garfield <[email protected]>: >> >>> On Wed, Nov 5, 2025, at 10:09 PM, Mikhail Savin wrote: >>> > Hi internals, >>> > >>> > I would like to propose adding a native values() method to the >>> BackedEnum >>> > interface that returns an array of all backing values. Before creating >>> a >>> > formal RFC, I'm seeking feedback on the concept and approach. >>> > >>> > == Summary == >>> > >>> > The proposal adds: >>> > >>> > interface BackedEnum { >>> > public static function values(): array; >>> > } >>> > >>> > This would allow: >>> > >>> > enum Status: string { >>> > case Active = 'active'; >>> > case Inactive = 'inactive'; >>> > } >>> > >>> > Status::values(); // ['active', 'inactive'] >>> > >>> > == Motivation == >>> > >>> > This pattern is extremely common in the wild. Based on GitHub code >>> search: >>> > >>> > * ~3,860+ direct implementations of this exact pattern >>> > * ~20,000-40,000 estimated real usage when accounting for shared >>> traits >>> > * Used in major frameworks: Symfony core (TypeIdentifier.php), >>> > Laravel ecosystem >>> > * Documented by PHP.net: The manual itself shows EnumValuesTrait as >>> > an example >>> >>> Correction: The manual does not show an EnumValuesTrait that I can >>> find. There is a *comment* in the manual that includes this method, but >>> that's not part of the manual proper, and frankly 90% of comments in the >>> manual should be removed. (cf: >>> https://www.php.net/manual/en/language.enumerations.traits.php#129250) >>> >>> > Common use cases: >>> > * Database migrations: $table->enum('status', Status::values()) >>> > * Form validation: $validator->rule('status', 'in', Status::values()) >>> > * API responses: ['allowed_statuses' => Status::values()] >>> > >>> > == Implementation == >>> > >>> > I have a working implementation with tests: >>> > https://github.com/php/php-src/pull/20398 >>> > >>> > The implementation: >>> > * Mirrors the existing cases() method structure >>> > * Extracts the value property from each case >>> > * Returns an indexed array (0, 1, 2, ...) >>> > * Only available on BackedEnum, not UnitEnum >>> > * All tests pass >>> >>> I am unclear why this is a major advantage over >>> array_column(Status::cases(), 'value'); >>> >>> > == Backward Compatibility - Important Discussion Point == >>> > >>> > This is a breaking change. Enums that already define a values() method >>> > will fail with: >>> > >>> > Fatal error: Cannot redeclare BackedEnum::values() >>> > >>> > Based on ecosystem research: >>> > * ~24,000-44,000 enum instances will break >>> > * All implementations are functionally identical to what's being >>> proposed >>> > * Migration is mechanical: just delete the user-defined method >>> >>> This is a hard-stop. There are hundreds of thousands of packages in the >>> wild that need to support multiple PHP versions. Nearly all packaglist >>> packages (which I presume is where you're drawing the research from; either >>> that or GitHub which will give a similar result set) support at least two >>> consecutive versions, if not 4, 5, or 6. >>> >>> A hard break like this would essentially mean the packages containing >>> those 40,000 enums would be unable to support both PHP 8.5 and 8.6 at the >>> same time. That's simply not an acceptable impact on the ecosystem, >>> regardless of how nice the feature may or may not be. >>> >>> --Larry Garfield >>> >> >> We could add a virtual $values property. Since enum properties are not >> allowed in userland, it will not break any existing code. >> >> — >> Valentin >> > > Hi all, > > Thank you for the thoughtful feedback. Based on the discussion so far, the > consensus seems to be: "the feature is useful, but the BC break is too > large." > > To address this, I've adjusted the proposal so that user code is allowed > to > redeclare values() on backed enums. This keeps existing projects working > unchanged while providing the native implementation for new code. > > The native values() will only be added when not already defined: > > ```c > if (!zend_hash_exists(&ce->function_table, ZSTR_KNOWN(ZEND_STR_VALUES))) > { > ... > } > ``` > > Result: > * Zero BC break - existing code unchanged > * New enums get values() automatically > * Libraries can maintain their implementation for older PHP support > > Trade-off: > I recognize this makes values() the only overridable enum intrinsic > (unlike cases/from/tryFrom). I'll document this clearly and add tests > to lock down the behavior. If needed, we can deprecate user-defined > values() in a later 8.x and make it an error in PHP 9.0. > > Questions: > 1. Is allowing values() override technically acceptable? > 2. Is documenting the inconsistency sufficient? > 3. Should we add deprecation? > 4. Can I submit RFC for this feature? > 5. Should I rather implement it via virtual property, as Valentin > suggested above? > > I updated the PR, and also added a few tests for this behavior. > > Thoughts? > > Best regards, > Savin Mikhail > Hi I am going to create RFC page, cuz badge "Status: requires RFC" was added to PR: https://github.com/php/php-src/pull/20398 Could someone please grant me RFC wiki karma so I can create the page https://wiki.php.net/rfc/add_values_method_to_backed_enum from my account (login - msavin)?
