Table of Contents

PHP RFC: Add values() Method to BackedEnum

Introduction

Backed enums frequently need an indexed list of their backing values (int|string). Today this is commonly implemented in userland using a helper method or a trait.

The pattern is widespread and implemented many times across the ecosystem.

GitHub code search (2025-11-12) found roughly:

More info about this research you can find in PR.

This RFC proposes adding a native values() static method to the BackedEnum interface that returns an indexed array of all backing values in declaration order. By doing that I hope to standardize the most common helper into a native method and reduce boilerplate across projects.

To avoid fatal errors from method name collisions with existing userland implementations, the native implementation is registered only if the enum does not already define a values() method (including via traits). The interface declaration intentionally has no return type.

<?php
 
enum Status: string {
    case Active = 'active';
    case Inactive = 'inactive';
    case Archived = 'archived';
}
 
var_dump(Status::values());
// ['active', 'inactive', 'archived']
 
?>

Common use cases include:

Proposal

Add the following method to the BackedEnum interface:

<?php
 
interface BackedEnum extends UnitEnum
{
    /**
     * Returns an indexed array of all backing values for the enum cases.
     *
     * @return int[]|string[]
     */
    public static function values();
}
 
?>

Semantics when the native implementation is used:

Backward Compatibility

The RFC aims to avoid method name collisions with existing code bases by combining two design choices:

As a result, existing enums that already define values() keep their behavior unchanged. New enums (or enums without a user-defined values()) get the native implementation automatically.

Trade-off: values() becomes the only built-in enum-related method that may be user-defined, while cases(), from() and tryFrom() are always native.

Why not a one-liner?

Today users can write:

<?php
$values = array_column(Status::cases(), 'value');
?>

However, a native values() method:

The large number of existing implementations suggests that the ecosystem repeatedly needs this helper.

Proposed PHP Version(s)

Next PHP 8.x (PHP 8.6)

RFC Impact

To the Ecosystem

IDEs, Language servers, static analyzers, polyfills might need to update their stubs to reflect docblock from updated BackedEnum interface

To Existing Extensions

No impact.

To SAPIs

No impact.

Open Issues

The following points were raised during discussion and are explicitly called out for voters to consider:

Future Scope

Optional: Future Convergence on Mandatory values()

If the community later prefers full consistency (non-overridable values() like other enum methods):

Phase 1 (PHP 8.x): Emit E_DEPRECATED for user-defined values()

<?php
enum Status: string {
    case Active = 'active';
 
    public static function values(): array { ... }
    // Deprecated: Status::values() is provided natively and should not be redeclared
}
?>

Phase 2 (PHP 9.0): Make user-defined values() an error

This gives the ecosystem years to migrate while eventually achieving full API consistency.

This future scope is NOT part of the current RFC - just documenting the possibility.

Implementation

Implementation is provided in PR https://github.com/php/php-src/pull/20398.

High-level changes:

Alternatives Considered

Voting

This is a Yes/No vote, requiring a 2/3 majority.

Voting will start later

References

The results of GitHub usage examples you can find in PR

Related RFCs:

Rejected Features

Interface WITH Return Type ('': array'')

An alternative implementation was considered where the interface would explicitly declare an : array return type:

<?php
 
interface BackedEnum extends UnitEnum
{
    public static function values(): array;  // ← WITH return type
}
 
?>

Advantages:

Why rejected:

Comprehensive GitHub search analysis found 6,800 existing values() implementations:

Category Count %
Compatible: : array return type 6,200 91.2%
Missing return type 64 0.9% ❌
Incompatible: other types (: string, : Iterator, etc.) 7 0.1% ❌
Unaccounted ~529 ~7.8% ❓
Total potential BC breaks 71-600 1.0-8.8%

Example breaking code:

<?php
 
enum Status: string {
    case Active = 'active';
 
    public static function values() {  // ❌ Missing : array
        return array_column(self::cases(), 'value');
    }
}
// Fatal error: Declaration of Status::values() must be compatible
// with BackedEnum::values(): array
 
?>

While 91.2% of implementations already have the correct signature, breaking even 1-9% of the ecosystem (71-600 codebases) was deemed unacceptable for a convenience feature.

Solution chosen: Omit return type from interface. This allows all existing implementations to remain compatible while the native implementation still returns a proper array.

Future consideration: Stricter typing with : array could be reconsidered for PHP 9.0 (major version where BC breaks are more acceptable), with a deprecation period in PHP 8.x.

Mandatory Native Implementation (Breaking Change)

Initially considered making values() always native and non-overridable (like cases()/from()/tryFrom()).

Rejected because:

Conditional approach chosen instead: Provides the convenience method while avoiding widespread breakage from name collisions in existing code.

Alternative Method Names

getValues(): More verbose, doesn't match cases() style toArray(): Ambiguous - case objects or values? Names or values? valueList(): Unnecessarily verbose extractValues(): Too long, unclear

Decision: values() best matches:

Virtual/Magic Properties

Suggestion to use Status::$values instead of Status::values().

Rejected because:

User-land Trait in Standard Library

Suggestion to provide standard library trait instead of native method.

Rejected because:

Why not use array_column(self::cases(), 'value')?

A common workaround today is:

<?php
$values = array_column(Status::cases(), 'value');
?>

This RFC proposes a dedicated method anyway for these reasons:

The goal is not to enable something impossible in userland, but to make the common pattern consistent and self-documenting.

Changelog