On Wed, Jul 9, 2025, at 15:29, Deleu wrote:
> Hi people!
> 
> Today I tried to do `ResourceType::from()` and was surprised that my IDE 
> immediately screamed at me. After further investigation, I realized that 
> Basic Enums (this is what the RFC called it [1]) does not have these 
> commodities backed into them.
> 
> I did some digging and I found 2 main discussions: Stringable by default 
> [2][3] and backed-in commodities [4]. I think Benjamin, Derick and Nicolas 
> have argued why Stringable by default may not be desirable and I only mention 
> this for completeness of the conversation. I don't want to talk about that at 
> all. Instead, I want to focus on the other side: construct from string by 
> default (from/tryFrom()).
> 
> I also read Larry's post that has been shared throughout these discussions 
> [5] and it seems fair and sound to use guardrails to discourage unintended 
> use. This gets into the territory of "let me do what I want, I know what I'm 
> doing" vs "let me limit what you can do because I built it and I know exactly 
> what it was intended for", which I also want to try and steer away from 
> debating, each camp has its merits.
> 
> Bilge said:
> 
>> My question, then, is why can't basic enumerations have these semantics by 
>> default? Or, to state it more concretely, what would be the downside to 
>> having all "basic" enumerations actually being "backed" enumerations whose 
>> values implicitly mirror their names for the purposes of converting to/from 
>> strings? Would this not make basic enumeration more useful without any 
>> particular downsides?
> 
> While I'm searching for similar clarification, I want to pose the question 
> differently. I feel like the answer to his question is in Larry's article 
> about discouraging fancy strings. My question boils down purely to: *can 
> Basic Enums implement ::from() / tryFrom() methods?*
> **
> Larry said:
> 
>> [...] In your case, you want to "upcast" a string to an enum. That means 
>> you're doing some sort of deserialization, presumably. In that case, a 
>> backed enum is what you want. *A unit enum isn't serializable, by design.*
> 
> Although this starts to thread into very pedantic territory, I think, in 
> fact, a *unit enum* (assuming it means Basic enum) is in fact always 
> serializable to a string: `$enum->value`. By design, the value is a string 
> and it cannot have duplicate values in a single enum. It means it's extremely 
> easy to define an Enum in PHP and at some point store it in a storage engine 
> / database in the form of `$enum->value`. Now if I want to get back my Enum 
> at a later stage I need to implement exactly the same code that already 
> exists in the PHP engine behind `Enum::from()`. Maybe it's not serializable 
> in the sense that it doesn't implement any true serialization mechanism, 
> which I'm guessing a backed-enum probably does, but I'm trying to come from 
> the very practical application of creating a Basic Enum at an HTTP context 
> (which is the bread and butter of PHP) and then recovering said Enum in a 
> background worker context without having to use PHP `serialize()` function 
> and store PHP-specific dialect in a database that is used by multiple teams 
> and programming languages.
> 
> I also take the point that it is easy to argue against all this: just put `: 
> string` on your Enum and duplicate the names with values. Still, this doesn't 
> address the "surprise effect" of "why this Enum doesn't have ::from() in 
> it?". There doesn't exist any other value (string or otherwise) that could be 
> used in ::from() or ::tryFrom() in a Basic Enum, which could make it less 
> contentious. Also, in the spirit of NOT making Enums "Fancy strings", I'm 
> looking for ways to reconstruct my Enum and all the behaviors available 
> inside of it without even having to associate or think about a string. The 
> only reason a string comes into the discussion is because $enum->value is one 
> and is stored. I also checked and:
> 
> enum Foo {
>     case 1;
>     case 2;
> }
> 
> is a parse error. [6].
> 
> Larry has also suggested that instead of making Basic Enum implement 
> `::from()` and `::tryFrom()` we could instead offer auto-populated 
> String-Backed Enum values. That means transforming this:
> 
> ```
> enum Foo: string {
>     case Bar;
>     case Baz;
> }
> ```
> (which is a Fatal Error today) into this:
> 
> enum Foo: string {
>     case Bar = 'Bar';
>     case Baz = 'Baz';
> }
> 
> I also like this proposal. Although semantically, I think it would be better 
> / have been better to have Basic Enum implementing the ::from() methods, one 
> could argue that adding it now could be a breaking change since people could 
> have Basic Enum already implementing their own custom ::from() method.
> 
> In conclusion, the "complex" (as opposed to primitive) object Enum is not a 
> Fancy String and where I'm coming from I believe to be in sync with that 
> mindset. However, PHP is highly used in Web context where we may need to use 
> asynchronous processes to make API calls fast and schedule executions at a 
> different context which often involves serialization. As such, being able to 
> reconstruct a Basic Enum seems a rather fundamental need that we can still 
> make it viable by making a small `: string` change to the Enum and opting-in 
> into the from / tryFrom utilities. This should not affect Int-Backed Enums at 
> all. 
> 
> Where casing is concerned (camelCase, PascalCase, snake-case, etc) [7], one 
> can argue that if you want to have full control over casing, you should 
> definitely take control over the values of your Enum. The beauty (in my mind) 
> about making it default to the enum name is that it doesn't matter if I 
> follow PER-CS rules or not, the truth is I don't need to think about strings 
> at all because my Enum is not a Fancy string.
> 
> I didn't intend to write such a long email, but I'm really keen on hearing 
> arguments against everything I shared to see if there are any flaws in my 
> thought process.
> 
> [1] https://wiki.php.net/rfc/enumerations#basic_enumerations
> [2] https://externals.io/message/118040
> [3] https://externals.io/message/124991
> [4] https://externals.io/message/123388
> [5] https://peakd.com/hive-168588/@crell/on-the-use-of-enums
> [6] https://3v4l.org/cDISV#v8.4.10
> [7] https://externals.io/message/123388#123394
> 
> --
> Marco Deleu

Hey Marco,

I think this relies on whether the “natural value” of a unit enum is a string 
or not. It might be, or it might not be. I don’t think you have a compelling 
argument on why it is a string and that string is the name. Personally, I used 
int-backed enumerations far more so I would argue that the natural value is an 
integer, not a string. I’ve been thinking of a “quality-of-life RFC” for 
obvious enums, for some time now. Basically, backed enums without a value 
receive the “obvious” value. So a string backed enum gets the name, while an 
int gets the ordered number. 

I think something like that makes more sense than trying to decide what the 
“natural value” of a unit enum is. 

— Rob

Reply via email to