[RFC] [Discussion] BackedEnum::values() - Seeking feedback before formal RFC

From: Date: Thu, 06 Nov 2025 04:09:18 +0000
Subject: [RFC] [Discussion] BackedEnum::values() - Seeking feedback before formal RFC
Groups: php.internals 
Request: Send a blank email to internals+get-129107@lists.php.net to get a copy of this message
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 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 == 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 The break is justified because: 1. Behavior is unchanged - native implementation does exactly what users already implemented 2. Migration is trivial - simply remove the redundant method 3. Precedent exists - PHP 8.1 native enums broke myclabs/php-enum (4.9k stars) similarly 4. Long-term benefit - standardization, discoverability, elimination of boilerplate 5. No alternative - virtual properties are technically infeasible; different name doesn't match community expectations == Questions for Discussion == 1. BC break acceptability: Given the scope and straightforward migration, is this break acceptable? 2. Method name: values() matches community usage (3,860+ examples) and parallels cases(). Alternatives like getValues() or toArray() were considered but seem inferior. Thoughts? 3. Target version: Currently targeting PHP 8.6 (master branch). Is this appropriate? 4. Deprecation period: Should we emit E_DEPRECATED in 8.5 and fatal error in 9.0? Or accept the break immediately? (Deprecation adds engine complexity and delays benefit.) == Prior Art == * Symfony: Uses this pattern in core components * PHP.net Manual: Documents EnumValuesTrait approach * TypeScript: Object.values(Enum) * Python: [e.value for e in Enum] * myclabs/php-enum: Had values() method (4.9k stars) == Next Steps == If feedback is generally positive, I will: 1. Request RFC karma 2. Create formal RFC on wiki.php.net 3. Address any concerns raised in this discussion 4. Move to formal voting after discussion period == Implementation Details == For those interested in the technical details, the PR includes: * Core implementation in zend_enum.c * Stub file updates * Comprehensive test coverage (9 test files) * Reflection support * Documentation in NEWS and UPGRADING PR: https://github.com/php/php-src/pull/20398 Looking forward to your feedback! Best regards, Savin Mikhail GitHub: @savinmikhail

« previous php.internals (#129107) next »