rfc:treat_enum_instances_as_values

PHP RFC: Treat Enum Instances as Values

Introduction

From the RFC template's opening quote, this RFC aims to be “pragmatic”, “loosely typed” and cater to all camps observed in the debate (as found to date.)

This RFC proposes to allow the use of enum instances as array keys in PHP. More specifically, where errors are produces in any context where an enum instance is used without ->value or ->name, the engine should instead assume ->value.

This change aims to enhance the usability and consistency of enums in PHP by treating enum instances as symbols of their respective values - especially in the context of array keys. This will allow large amounts of existing code in various C-style languages to be compatible with PHP usage without affecting current projects.

Further, this proposal provides potential future RFC a path to enable array key type constraints in line with present == vs === semantics and ArrayAccess, without drastic engine overhauls.

Proposal

Given that enums already exist in PHP and enum cases are mapped to either ints or strings exclusively, we propose the following changes:

Enum instances should be allowed to be used as array keys without producing an error. When an enum instance is used as an array key, it should be treated as a symbol of its value. UnitEnum , not backed as an int or string, should treat value as an unsigned integer iterating from 0, more specifically modeling the relationship of enumeration (as a mathematical construct) with the natural numbers.

Example: Consider the following enum and array:

 enum Color: int {
     case red = 1;
     case green = 2;
     case blue = 3;
 }
 enum WeekDays: int {
     case monday = 1;
     case tuesday = 2;
     case wednesday = 3;
 }
 $palette = [
     1 => 'Red',
     2 => 'Green',
     3 => 'Blue',
 ];

Currently, the following code produces an error:

 Color $red = Color::red;
 $paint = $palette[$red];  // Error

With this proposal, the code above should not produce an error and should work as expected:

 Color $red = Color::red;
 $paint = $palette[$red];  // 'Red'

Last on a more opinionated note; the author suggests that enum cases are userland symbols and should imply value. Just as there is no need in the following scenario:

 $a = 1;
 $b = '2';
 $list = [
   $a => 'some value',
   $b => $some_value;
 ];

vs

 $list = [
   $a->value => 'some value',
   $b->value => $some_value;
 ];

Backward Incompatible Changes

There are no backward-incompatible changes introduced by this proposal.

Proposed PHP Version(s)

Next PHP 8.x.y

RFC Impact

To SAPIs

None

To Existing Extensions

None

To Opcache

Implementation being studied. None expected. Enums may not need some checks.

php.ini Defaults

Could be a toggle if community desired

Future Scope

While this proposal originated in a issue with wide support, referenced below, we consider strongly the negative feedback which all surrounded adding greater type mechanics to keys.

Presently there are many proposals in the history of PHP regarding object keys, direct overloading of the [ ] operators and a wide arrangement of considerations around typing. We propose that many of these wishes can be addressed with much less effort if we begin at the loose typing and iteratively add stronger typing.

From present knowledge, the PHP internals teams have found methods of using specific classes of objects as keys but not a road to generic objects. If enum labels ever meet this criteria in their own right, as references to enum instances, such an implementation will take precedence over this RFC. Semantics would be the same in either case, however userland glue code can enable usage patterns which inform future development by enabling this present RFC.

Future RFCs are recommended to enable

 Day::Monday == Color::Red  //true
 Day::Monday === Color::Red //false

Which could in turn allow

 class MyType implements ArrayAccess
 //...
 
    public function offsetGet(Month $which){
       //...
    }
 
 //...
 }
 class YourType implements ArrayAccess
 //...
 
    public function offsetGet(mixed $which){
       //...
    }
 
 //...
 }

Making the desirable

 $myobj = new MyType();
 $yourobj = new YourType();
 $x = $myobj[Color::Yellow];   // error
 $y = $yourobj[Color::Yellow]; // fine

Such a roadmap finally enables users to user to simply use match($this) and other userland syntactic sugar to simulate object keys. This gap can be further reduced and optimized from there.

Proposed Voting Choices

A two-thirds majority is required for this proposal to be accepted.

Patches and Tests

Pending

Implementation

Author's org has committed work on this issue and having it implemented, assuming community is in favor and this is not trivial for an existing member. Any guidance from those who have worked previously with enums is appreciated.

References

A robust discussion about further pros/cons/considerations at the original issue - https://github.com/php/php-src/issues/9208

Mailing list introduction and opening RFC- https://news-web.php.net/php.internals/120117

Mailing list post-RFC discussion: TBD

Rejected Features

None to date

rfc/treat_enum_instances_as_values.txt · Last modified: 2023/04/29 11:04 by suitespacernd