Enums should implement Stringable interface by default

php.internals

Janis Kajaks

1 year ago
Hi, I'm writing this email with a reference to https://wiki.php.net/rfc/howto. My suggestion is that all enums (both basic/pure and backed) should implement Stringable interface by default, and before you say that it's totally wrong or impossible let me explain why. Let's say I have a backed enum: enum Suit: string { case Hearts = 'H'; case Diamonds = 'D'; case Clubs = 'C'; case Spades = 'S';} Now if I'm trying something like this "echo Suit::Hearts;"I will get an error "Fatal error: Uncaught Error: Object of class Suit could not be converted to string" BUT if I'm trying to use this enum as a part DTO (data transfer object) and then serialize it or do something as simple as "echo json_encode(Suit::Hearts);" then suddenly PHP knows how to convert enum to string. This feels so unfair to me that I finally decided to write this email. The same applies to basic enums which have only case names, but they are still stringable as $enum->name. Please give me the initial feedback to understand if it's worth proceeding with a RFC or not. Best regards, Janis Kajaks

Rowan Tommins [IMSoP]

1 year ago
On 28/02/2025 08:33, Janis Kajaks wrote:
> My suggestion is that all enums (both basic/pure and backed) should > implement Stringable interface by default,
This has come up at least twice before: * https://externals.io/message/118040 * https://externals.io/message/124991 These threads also touch on some of the same issues: * https://externals.io/message/120121 * https://externals.io/message/123388 Fundamentally, there are different schools of thought on what an "enum" should be, which lead to different sets of features. I think some of those differences are fundamental enough that you could only have both if the language had multiple enum-like things which the user could choose between.
-- Rowan Tommins [IMSoP]

Larry Garfield

1 year ago
On Fri, Feb 28, 2025, at 10:11 AM, Rowan Tommins [IMSoP] wrote:
> On 28/02/2025 08:33, Janis Kajaks wrote: >> My suggestion is that all enums (both basic/pure and backed) should >> implement Stringable interface by default, > > > This has come up at least twice before: > > * https://externals.io/message/118040 > * https://externals.io/message/124991 > > These threads also touch on some of the same issues: > > * https://externals.io/message/120121 > * https://externals.io/message/123388 > > Fundamentally, there are different schools of thought on what an "enum" > should be, which lead to different sets of features. > > I think some of those differences are fundamental enough that you could > only have both if the language had multiple enum-like things which the > user could choose between.
Also see: https://peakd.com/hive-168588/@crell/on-the-use-of-enums Not auto-implementing Stringable was a deliberate design decision, for reasons that have not changed. --Larry Garfield

AllenJB

1 year ago
So to summarize the proposed behavior (as I understand it): * If an enum is backed, it auto-casts to ->value * If an enum is not backed, it auto-casts to ->name I believe this has the following problems (at least): * Unbacked enums are not supposed to be representable as scalar values - if I, as a developer, intended an enum to be representable as a scalar, it would be backed; * Different behavior depending on whether the enum is backed or not is confusing; * If an unbacked enum is created, then later a developer wants to change it to backed, it can break code / change output in unexpected, and in ways that are very difficult to search for. You need to, at least, not just search for usages of the enum, but usages of the properties/variables which can be that enum (and repeat recursively for further assignments), then work out which of those might involve auto-casting. (This sort of change probably isn't very common, but that doesn't mean it should be made a nightmare when someone does want to do it) I don't think enums should ever auto-cast to scalar values (backed or not) Venturing further down this road starts getting into what I suspect is dangerous territory, with obvious examples being: * enums as array keys (which I would like to be able to do, but not via this sort of auto-casting) * comparing different enums with the same backed values (or even different unbacked enums with the same ->name) And that's without looking at potential conflicts this behavior would bring with planned features such as https://wiki.php.net/rfc/adts My personal opinion on the current json_encode() behavior with backed enums here (and anywhere else where's there's similar auto-casting behavior) is that it's undesirable and it should be an error. I think it's completely ambiguous as to what the author intended (or if they even intended to at all) when representing a backed enum in JSON. If you do want this behavior in your application in cases such as json_encode(), it's pretty easy to write a wrapper or helper that casts values as desired. I've done this with database level code (eg. casting bool to 1/0 for MySQL, as a simple example).