Newsgroups: php.internals Path: news.php.net Xref: news.php.net php.internals:127973 X-Original-To: internals@lists.php.net Delivered-To: internals@lists.php.net Received: from php-smtp4.php.net (php-smtp4.php.net [45.112.84.5]) by lists.php.net (Postfix) with ESMTPS id AC8BE1A00BC for ; Wed, 9 Jul 2025 14:39:04 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=php.net; s=mail; t=1752071834; bh=nf1lRXoAbb6XTlzYBua476XrbWocLYMuY/CwBJFuZ/8=; h=References:In-Reply-To:From:Date:Subject:To:Cc:From; b=JOuAAGo6N2sl37qvF5yyGdkVkQyLotS9hebMpWs1lOPV8JomJeTGHX6+HeKWuOlrn ahNbzOKWIjNh9eQDg6wJ8q2ix94zt4UlXqPvgxO2qJ2u8qCOttfEpxC7mz3NVxmgTC n5SG/+m+2KzE0o2cd8yMLOEmZugSpg/MzdFNc3HPfyxpaI5VljBVQCDgItIesbU1cR n+sK+71ZYhYNF2iRoVn8F//6XK1sErzBhzmXsfvUIzqVsWoRYzaZJj0LyNlhPZzgiZ 4BDHbLNZtBkmNuphzcO8a/NEsfy6ZIbeCQyaqy5S5iESB1nEgAeAPyBLYmu3Haw6Sp t26t7/CCUiDlQ== Received: from php-smtp4.php.net (localhost [127.0.0.1]) by php-smtp4.php.net (Postfix) with ESMTP id 1BB591805BF for ; Wed, 9 Jul 2025 14:37:13 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 4.0.1 (2024-03-25) on php-smtp4.php.net X-Spam-Level: X-Spam-Status: No, score=-0.2 required=5.0 tests=BAYES_40,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,DKIM_VALID_EF,DMARC_PASS,FREEMAIL_FROM, HTML_MESSAGE,RCVD_IN_MSPIKE_H3,RCVD_IN_MSPIKE_WL,SPF_HELO_NONE, SPF_PASS autolearn=no autolearn_force=no version=4.0.1 X-Spam-Virus: Error (Cannot connect to unix socket '/var/run/clamav/clamd.ctl': connect: Connection refused) X-Envelope-From: Received: from mail-ej1-f42.google.com (mail-ej1-f42.google.com [209.85.218.42]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by php-smtp4.php.net (Postfix) with ESMTPS for ; Wed, 9 Jul 2025 14:37:12 +0000 (UTC) Received: by mail-ej1-f42.google.com with SMTP id a640c23a62f3a-ae0b2ead33cso4139666b.0 for ; Wed, 09 Jul 2025 07:39:02 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20230601; t=1752071942; x=1752676742; darn=lists.php.net; h=cc:to:subject:message-id:date:from:in-reply-to:references :mime-version:from:to:cc:subject:date:message-id:reply-to; bh=2Y+59/j1VrffKyyJlgupqnRVzDfLh06yJWN8OEgPHV0=; b=YVbHpb2ML2NsIMmK9Q59NZ4Ru6TOHjfUfkfUuP+xMjsUZTniXVBjwYszIrGKdz9YCl KrrTSiiN5uxp/8shBTMuC6mLs1BXjclGm3smcntmfCPdGYsVGP3yGbCf40I6Ns1NIIBh ZzPz2itw/g5na2UvPJcruDArK4Qn5rA6kBOm0y+62Jcu3nQB7Y7QYYtLRxBdaYq2sw9j LEJMYsYQq6i9+6pZUNk2VDBDxMFFjNsA5WAu7Y+WhJzeMBC2ZcDFW8mIM1LvvkuYZanT /mntq9fRXKH1MbkFTYDkzQFa3wbQEOcQQWjn7I/MAGXEb9g/B7aCJMyD9o7LjH2J54Dv ZUeg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1752071942; x=1752676742; h=cc:to:subject:message-id:date:from:in-reply-to:references :mime-version:x-gm-message-state:from:to:cc:subject:date:message-id :reply-to; bh=2Y+59/j1VrffKyyJlgupqnRVzDfLh06yJWN8OEgPHV0=; b=YGtnamc7aY0qTYVdh6R8hIMzS85hmLXJzyuADhZwn013j0XK7PLafIxgaxKVMXVDP3 GQFuam+wjMbXNjHnCjsh5Z/cE3ExFtZF4lUoTwZVxVngP0WBkfXyeBlBETxztyOaSbdI 5Cg9SM1Y2gPSUoQ8TD6vGm7iFGAveyZ91IhdDFyyf2CsD+Y6M7gpdwRlxWoHGIpsYJqr z80H5rY9jeVie/bAe+Y6vyLYSk0ffKjn82GdDeXu3J/lbudF9MvXHxV7nBBQm09AszVR ocqpHL7hdu9bYaecRPtjo850Pv0bi4ByrN7D73DivKq2TnPy+aSwy9v/7aQBpmO1Drsm 99KA== X-Gm-Message-State: AOJu0Yyg8TSVO24o4+4XzluQKsrWkk99As7NxOMHDE0BqMMW+2LsJEF7 Hvu/+sML0Ay1wBSj6uwnVAxqE2rDucsLKnfJoYbXjK2Yt0lq5fLlc5wLBk0OzWF/VNdnDdDFmsz +sRYLX060UGwaRd4m9sPYsplt0berERt+oA== X-Gm-Gg: ASbGnctn2AcB8t2shz6lf7/rzzw6rg/1A86UmXgAz4kpvDNC5kKZ57rqwxqW9rK2ni7 tuFjbsE5TM5yf03zdd/9rBRiby3eNYuubpI6B1dONbR33mtnDQv5+AEWLM3o8EIt8OILO5viTdl nJUQg3EA5cjohUFPA095ZoAGAazfY3uQPQD9T4a0RAFYNPWeYZ+b5cvYbnxGtv4aK3p6ByIO30+ w== X-Google-Smtp-Source: AGHT+IGcBRsn+MDqpCXs5wzlU29ov9yytIl+utArHnLAHhPWgXPOZYFHgAhJvGYpSeW8AzlIEP8wQffhlDJGHAmxoqM= X-Received: by 2002:a17:907:724a:b0:ae6:ab7c:1996 with SMTP id a640c23a62f3a-ae6d14bffddmr273468066b.29.1752071941336; Wed, 09 Jul 2025 07:39:01 -0700 (PDT) Precedence: bulk list-help: list-post: List-Id: internals.lists.php.net x-ms-reactions: disallow MIME-Version: 1.0 References: In-Reply-To: Date: Wed, 9 Jul 2025 16:38:34 +0200 X-Gm-Features: Ac12FXwCQgEAFqoQDRDK2pivvbrjkOi6mAiz6ckus4HpPEGo5rN3s1-omr1mVRY Message-ID: Subject: Re: [PHP-DEV] ::from() and tryFrom() on Basic Enums To: Deleu Cc: PHP internals Content-Type: multipart/alternative; boundary="000000000000af37cf063980093f" From: kjarli@gmail.com (Lynn) --000000000000af37cf063980093f Content-Type: text/plain; charset="UTF-8" Content-Transfer-Encoding: quoted-printable On Wed, Jul 9, 2025 at 3:33=E2=80=AFPM 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 Nicola= s > 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 discussion= s > [5] and it seems fair and sound to use guardrails to discourage unintende= d > 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 awa= y > from debating, each camp has its merits. > > Bilge said: > > My question, then, is why can't basic enumerations have these semantics b= y > default? Or, to state it more concretely, what would be the downside to > having all "basic" enumerations actually being "backed" enumerations whos= e > values implicitly mirror their names for the purposes of converting to/fr= om > 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 questio= n > 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 strin= g > 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 co= de > that already exists in the PHP engine behind `Enum::from()`. Maybe it's n= ot > serializable in the sense that it doesn't implement any true serializatio= n > 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 a= n > 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 otherwis= e) > that could be used in ::from() or ::tryFrom() in a Basic Enum, which coul= d > 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 behavio= rs > 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 =3D 'Bar'; > case Baz =3D '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 tha= t > 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 shou= ld > 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 hearin= g > 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 > It's important to keep in mind that when non-backed enums have a value by default, it will be used as such. When inevitably the assumption is made that a value can be used because it exists, and then the enum name is changed, the "from" will break as well. If I rename a case and someone else is using this in a database and neither of us consider the name to be changed, we're now stuck with datacorruption and broken code. I prefer this to remain separate as it is. --000000000000af37cf063980093f Content-Type: text/html; charset="UTF-8" Content-Transfer-Encoding: quoted-printable


On Wed, Jul 9, = 2025 at 3:33=E2=80=AFPM Deleu <del= eugyn@gmail.com> wrote:
Hi people!

To= day I tried to do `ResourceType::from()` and was surprised that my IDE imme= diately 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 defa= ult may not be desirable and I only mention this for completeness of the co= nversation. 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 guardr= ails to discourage unintended use. This gets into the territory of "le= t 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:

<= blockquote style=3D"margin:0px 0px 0px 40px;border:none;padding:0px">My que= stion, then, is why can't basic enumerations have these semantics by de= fault? Or, to state it more concretely, what would be the downside to havin= g all "basic" enumerations actually being "backed" enum= erations whose values implicitly mirror their names for the purposes of con= verting to/from strings? Would this not make basic enumeration more useful = without any particular downsides?

While I&#= 39;m searching for similar clarification, I want to pose the question diffe= rently. I feel like the answer to his question is in Larry's article ab= out discouraging fancy strings. My question boils down purely to: can Ba= sic 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 territor= y, I think, in fact, a unit enum=C2=A0(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 poin= t 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 exa= ctly 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 imple= ment any true serialization mechanism, which I'm guessing a backed-enum= probably does, but I'm trying to come from the very practical applicat= ion of creating a Basic Enum at an HTTP context (which is the bread and but= ter of PHP) and then recovering said Enum in a background worker context wi= thout having to use PHP `serialize()` function and store PHP-specific diale= ct in a database that is used by multiple teams and programming languages.<= /div>

I also take the point that it is easy to argue aga= inst all this: just put `: string` on your Enum and duplicate the names wit= h values. Still, this doesn't address the "surprise effect" o= f "why this Enum doesn't have ::from() in it?". There doesn&#= 39;t exist any other value (string or otherwise) that could be used in ::fr= om() 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 ins= ide of it without even having to associate or think about a string. The onl= y reason a string comes into the discussion is because $enum->value is o= ne and is stored. I also checked and:

enum Foo {
=C2=A0 = =C2=A0 case 1;
=C2=A0 =C2=A0 case 2;
}

is a parse error. [6].

Larry has also sug= gested that instead of making Basic Enum implement `::from()` and `::tryFro= m()` we could instead offer auto-populated String-Backed Enum values. That = means transforming this:

```
enum Foo: string {=
=C2=A0 =C2=A0 case Bar;
=C2=A0 =C2=A0 case Baz;
}
```

<= /div>
(which is a Fatal Error today) into this:

enum Foo: string {
=C2=A0 =C2=A0 case Bar =3D 'Bar';
=C2=A0= =C2=A0 case Baz =3D 'Baz';
}

I also li= ke 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 hav= e Basic Enum already implementing their own custom ::from() method.

In conclusion, the "complex" (as opposed to pri= mitive) object Enum is not a Fancy String and where I'm coming from I b= elieve 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 f= ast and schedule executions at a different context which often involves ser= ialization. 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 `: stri= ng` change to the Enum and opting-in into the from / tryFrom utilities. Thi= s should not affect Int-Backed Enums at all.=C2=A0

Where casing is concerned (camelCase, PascalCase, snake-case, etc) [7], on= e can argue that if you want to have full control over casing, you should d= efinitely 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 kee= n on hearing arguments against everything I shared to see if there are any = flaws in my thought process.


--
<= div dir=3D"ltr">
Marco Deleu

It&= #39;s important to keep in mind that when non-backed enums have a value by = default, it will be used as such. When inevitably the assumption is made th= at a value can be used because it exists, and then the enum name is changed= , the "from" will break as well. If I rename a case and someone e= lse is using this in a database and neither of us consider the name to be c= hanged, we're now stuck with datacorruption and broken code. I prefer t= his to remain separate as it is.
--000000000000af37cf063980093f--