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

Reply via email to