-
Notifications
You must be signed in to change notification settings - Fork 8k
Add values() Method to BackedEnum #20398
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Conversation
|
Great and thorough study — the addition of this method seems highly anticipated, and I believe it's underrated because one of the most common approaches uses array_column :) |
|
I emailed the internals, now I'm waiting for the feedback |
|
Based on the feedback from the internals so far: consensus seems to be “the feature is useful, but the BC break is too large.” To address that, I’ve adjusted the proposal so that user code is allowed to redeclare I recognize this makes If, over time, the community prefers to consolidate on a single intrinsic (no redeclaration), we can introduce a deprecation phase in a later minor and make redeclaration an error in the next major. For now, the goal is to deliver the utility of |
|
@vudaltsov suggested to use virtual property $values for that, I am not sure would it be better than the current implementation (with redeclaring values() method), cuz it would be less consistent. Any thoughts? |
I understand the reasoning, but this would indeed be weird from a user point of view. |
|
@TimWolla Could you please grant RFC karma to user |
I'm afraid I don't have the necessary Wiki permissions. |
|
cc @iluuu1994 @cmb69 Can one of you please grant RFC karma? See https://externals.io/message/129107#129127 |
|
Yes. Though note that karma requests should happen in new threads. They are easily missed otherwise. |
|
Thanks, guys, for the help I created the rfc: https://wiki.php.net/rfc/add_values_method_to_backed_enum |
|
Updated the pr description according to discussion on RFC about 2 points: usage of array_column (found out +3.6k usages) and BC break in return type declaration |
|
I updated rfc and pr by removing interface return type declaration based on feedback from internals |
Add values() Method to BackedEnum
Summary
Introduce a native
BackedEnum::values()static method that returns the list of all backing values (int|string) of a backed enum's cases in declaration order. This eliminates boilerplate commonly implemented across projects and aligns with the existingcases()API.The interface declares the method without a return type to ensure zero backward compatibility breaks with 6,800+ existing implementations.
Target: master (PHP 8.6)
Motivation
The ecosystem repeatedly implements the same pattern to produce an array of enum values:
This pattern appears widely across GitHub and frameworks, often implemented directly or via traits (which hides usage from code search).
Quantitative Evidence
Direct implementations (comprehensive GitHub code search as of 2025-11-12):
array_column(self::cases(), 'value')array_map(fn($case) => $case->value, self::cases())return array_map+self::cases()+->valuereturn array_map+fn($case) => $case->valuefunction values()+return array_map+self::cases()function toArray()+array_map+self::cases()+->valuefunction getValues()+array_map+self::cases()function values()+foreachloop +->valueImplementation distribution:
array_columnpattern: 3,600 (48%) - most popular ✨array_mappatterns: 2,554 (34%)Trait pattern multiplier (2,900 results):
EnumValuesTrait) and thenuseit in dozens of enumsQualitative evidence (frameworks & libraries):
Providing a native
values()method:cases()nicely)Proposal
Add the following method to the
BackedEnuminterface:Semantics
array<int>; for string-backed,array<string>.Examples
Implementation
The interface declares the method without a return type to ensure zero backward compatibility breaks:
Characteristics:
array- proper type at runtimeBackward Compatibility Analysis
Comprehensive GitHub search analysis (2025-11-12) of existing
values()implementations:: arrayreturn type: string: int: Closure: iterable: Iterator: GeneratorBackward Compatibility
BC Breaks: ✅ ZERO (0%)
By omitting the return type from the interface, all existing implementations remain compatible. The native implementation always returns
array, but user-defined implementations can use any return type:Comprehensive GitHub search analysis (2025-11-12) found 6,800 existing
values()implementations:: arrayreturn type: string,: Iterator, etc.)Implementation Details
Engine changes (Zend)
Add stub and arginfo:
Zend/zend_enum.stub.php: addBackedEnum::values()signature without return typeZend/zend_enum_arginfo.h: regenerated (committed)Add interned string identifier:
Zend/zend_string.h: addZEND_STR_VALUES("values")Implement and register the method:
Zend/zend_enum.c:zend_enum_values_func(), extracting thevalueproperty from each caseTests
Reflection tests:
ext/reflection/tests/BackedEnum_values_reflection.phpt- ensure method appearsext/reflection/tests/ReflectionEnum_toString_backed_int.phpt- update toStringext/reflection/tests/ReflectionEnum_toString_backed_string.phpt- update toStringEnum behavior tests:
Zend/tests/enum/backed-values-int.phpt- int-backed enum valuesZend/tests/enum/backed-values-string.phpt- string-backed enum valuesZend/tests/enum/backed-values-empty.phpt- empty enum edge caseZend/tests/enum/backed-values-order.phpt- declaration order preservationZend/tests/enum/backed-values-not-on-pure.phpt- pure enums don't have values()Zend/tests/enum/backed-values-ignore-regular-consts.phpt- regular constants ignoredZend/tests/enum/backed-values-user-defined.phpt- user-defined values() overrides nativeZend/tests/enum/backed-values-user-defined-incompatible.phpt- different return types allowedDocumentation in-tree
NEWS: announce the feature under CoreUPGRADING: List under "New Features" (no BC section needed - zero breaks)Manual (php/doc-en)
To be added in a separate PR:
values()signature, description, examplesvalues()alongsidecases()/from()/tryFrom()BackedEnum::values()Performance
Native implementation provides:
array_column(self::cases(), 'value')Benchmark (100,000 iterations):
Reference: https://3v4l.org/Q5AYg
Note:
array_columnis the most popular pattern (48% of implementations, 3,600 results) and is ~3x faster thanarray_map.Alternatives Considered
Different method name
getValues(),valueList(): More verbose, doesn't matchcases()styletoArray(): Ambiguous - case objects or values? Names or values?Decision:
values()best matches:cases()Virtual/magic properties
Status::$valuesinstead ofStatus::values()Rejected:
cases(),from(),tryFrom()(all methods)Impact on Ecosystem
Positive impacts
arraytypevalues()without boilerplateRejected Features
Interface WITH Return Type (
: array)An alternative approach was considered where the interface would explicitly declare
: arrayreturn type:Advantages:
cases(): arraysignatureWhy rejected:
This approach would cause BC breaks affecting 1.0-8.8% of existing implementations (71-600 codebases):
: arrayreturn typeExample breaking code:
While 91.2% of implementations already have the correct signature, breaking even 1-9% of the ecosystem was deemed unacceptable for a convenience feature. The chosen approach (no return type) provides the same functionality with zero disruption.
This stricter typing could be reconsidered for PHP 9.0, where major BC breaks are more acceptable, with a deprecation period in PHP 8.x.
Prior Art
No previous RFCs proposing a
BackedEnum::values()method were found.Related RFCs
Review of the PHP RFC index shows enum-related proposals:
None address adding a convenience method returning backing values.
Other languages
Object.values(EnumType)[e.value for e in EnumType]values()method (4,900 stars, pre-8.1)Checklist
Links
Thank you for reviewing!