Newsgroups: php.internals Path: news.php.net Xref: news.php.net php.internals:127970 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 71DDD1A00BC for ; Wed, 9 Jul 2025 13:30:02 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=php.net; s=mail; t=1752067691; bh=bijxV7FQuHvz0wv6VxiXV1C9MNYczDs1BKxaU89lufk=; h=From:Date:Subject:To:From; b=SQJq44T0eJqm6fgp38HukrJ88klnR2k8QKOJWcwUnNH8vLL6lvBiBnEhK1IHyrjrA 7tmv+uDkM9f/TGzaZwF/lubKQuZ0MH0Jw074lqwmE868kXFRMf0dSvytP9k2sqT/2h gZ2KaWwgFioc9mmEvYGnuJvjGgSMBehShr9Uy12vJMrRgZUi6Wg/oyR6fm8geNvdYI rOGizeubTNM4ROLq5keFBYP0PPnsxp1MKs4/RFKSkyaAvykNn7pXJ6js7MrK03ovc4 69TulAvhCIJuRHw0mSfTuAvqvjYXp3ahocc7qwTpUFDXWdr34BX5FhTu58uevUj4or Z3f/fblQ0vQOg== Received: from php-smtp4.php.net (localhost [127.0.0.1]) by php-smtp4.php.net (Postfix) with ESMTP id E387D180068 for ; Wed, 9 Jul 2025 13:28:10 +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.4 required=5.0 tests=BAYES_50,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,DKIM_VALID_EF,DMARC_PASS,FREEMAIL_FROM, HTML_MESSAGE,RCVD_IN_DNSWL_NONE,RCVD_IN_MSPIKE_H2,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-yb1-f172.google.com (mail-yb1-f172.google.com [209.85.219.172]) (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 13:28:10 +0000 (UTC) Received: by mail-yb1-f172.google.com with SMTP id 3f1490d57ef6-e8b751f458fso15468276.3 for ; Wed, 09 Jul 2025 06:30:00 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20230601; t=1752067800; x=1752672600; darn=lists.php.net; h=to:subject:message-id:date:from:mime-version:from:to:cc:subject :date:message-id:reply-to; bh=Fex1mHTRTx8lVFu1ObpEKkdkh5+JeEhksRDA/reLBIw=; b=RKgsiGdhr2oRVJhd8PyGhXTysjwcvkTS4/5vpcvzrcPCJ7zufE1HKKcMNAwvGWhzTP +5Ug6Eb07VQMxnjZ1150mdSsTjMI/KXQS7oyV2BRiZtTc1ZkyHRZEcuEp6bAWB5xjjaV TNUZzmbSaHe6WOSCPIrg8qozuCdLsms3oj+v3R4nvsZBQbVkstA+PGZ8+MeB22yRyEtE n6MMhPNMsxC7/N+XA5t3Zs5ReKGos9XZE2IKPxDASCmgr/0+4rYmJTG5iB0/DQvz21C8 onrPhMU6JZip3G1nqHxxADcyrVdi8TfiOKT1yk80b2KQlX5sn5U66VV2ftdPZzFwNliJ b1yw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1752067800; x=1752672600; h=to:subject:message-id:date:from:mime-version:x-gm-message-state :from:to:cc:subject:date:message-id:reply-to; bh=Fex1mHTRTx8lVFu1ObpEKkdkh5+JeEhksRDA/reLBIw=; b=ay0y/mJYX4qviSmgXuk6apeF6W80sh5xQA9phpjo/JRYDm14SGPJ5rC7UwHnmCuemI DZIvKpE0sbYW0oDVcvjpxlZ4G2OE8hKP4/U37sRXEkptr1JgvcNYwi9ZDEmZyNKtaZRK RaEqm9p5rwTt2Txws+r8pxCi/0cg+pOatWPmST5NAkGW6njgermCe1+y7hqIjwGq3zNZ Z1vVmPZ07Af7Ja3pjC2+PWIWicwUkAri8cgEvAtI6M3r8BGLDAXQrnbKmpcILncLmbpo 5J1Za/UxV94UhfYI5Lkeq5J92gOcaE0APyhREWm/OAjRtF2ZiVxqbGddjUwKgOd3D+cJ sOlA== X-Gm-Message-State: AOJu0YxI9afmXIh+1uTqUdyNZIt+C4vOt/FlLDJTalcV7aIDObNRv6mp aB87cJSlZRcUL/s9gFVs0MDAizb6egQcFk97toPIx1+JqlrEz3yATv3do89u+6jLGX16X6BSicX QWerv29j33Qmkhts+GhTKfibpOBUVGfqU/Ku6Pis= X-Gm-Gg: ASbGncvAG0ZNPMA2K9BlhMBq9i58jrKDuNmLVWtzVk92hnOQ9UTFfw0k3Ssoo2jv9jt FgumNSOJOdX/p23cM0m3USoB8X7ob6z1XAqdR2+8SPBv4GwMAYMV/DeVkXkQaeFIDr+5SrIPI8G vopfb/gobjGY/FupOs2EfuwchVL4sfV73eDYNkZ1Ng3Mx/ykWNcDHTAuk= X-Google-Smtp-Source: AGHT+IExeJW1wHt4XcDy17mCVLbMlQxOUz1WhkrzkrbF3d/OAzDwFAH/gMB2OuHxJh7N9ryRyBEYou7T8KNUGnCyixo= X-Received: by 2002:a05:690c:9c07:b0:712:c5f7:1ef8 with SMTP id 00721157ae682-717b168be76mr15181707b3.2.1752067799861; Wed, 09 Jul 2025 06:29:59 -0700 (PDT) Precedence: bulk list-help: list-post: List-Id: internals.lists.php.net x-ms-reactions: disallow MIME-Version: 1.0 Date: Wed, 9 Jul 2025 10:29:23 -0300 X-Gm-Features: Ac12FXw7wCV11NWSICxN3HAhcTWdmPOqEVxVyWVTAYT_zjcRNubjCQz8vjzVakw Message-ID: Subject: [PHP-DEV] ::from() and tryFrom() on Basic Enums To: PHP internals Content-Type: multipart/alternative; boundary="000000000000d54f4506397f12b5" From: deleugyn@gmail.com (Deleu) --000000000000d54f4506397f12b5 Content-Type: text/plain; charset="UTF-8" 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 --000000000000d54f4506397f12b5 Content-Type: text/html; charset="UTF-8" Content-Transfer-Encoding: quoted-printable
Hi people!

Today I tried to = do `ResourceType::from()` and was surprised that my IDE immediately screame= d 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 the= m.

I did some digging and I found 2 main discussio= ns: Stringable by default [2][3] and backed-in commodities [4]. I think Ben= jamin, Derick and Nicolas have argued why Stringable by default may not be = desirable and I only mention this for completeness of the conversation. I d= on't want to talk about that at all. Instead, I want to focus on the ot= her side: construct from string by default (from/tryFrom()).

=
I also read Larry's post that has been shared throughout the= se discussions [5] and it seems fair and sound to use guardrails to discour= age 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", whic= h I also want to try and steer away from debating, each camp has its merits= .

Bilge said:

My question, then, is why c= an't basic enumerations have these semantics by default? Or, to state i= t more concretely, what would be the downside to having all "basic&quo= t; enumerations actually being "backed" enumerations whose values= implicitly mirror their names for the purposes of converting to/from strin= gs? Would this not make basic enumeration more useful without any particula= r downsides?

While I'm searching for si= milar clarification, I want to pose the question differently. I feel like t= he answer to his question is in Larry's article about discouraging fanc= y 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 a= n enum. That means you're doing some sort of deserialization, presumabl= y. In that case, a backed enum is what you want. A unit enum isn't s= erializable, by design.

Although t= his starts to thread into very pedantic territory, I think, in fact, a u= nit enum=C2=A0(assuming it means Basic enum) is in fact always serializ= able to a string: `$enum->value`. By design, the value is a string and i= t cannot have duplicate values in a single enum. It means it's extremel= y easy to define an Enum in PHP and at some point store it in a storage eng= ine / 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 alr= eady exists in the PHP engine behind `Enum::from()`. Maybe it's not ser= ializable 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 Enu= m at an HTTP context (which is the bread and butter of PHP) and then recove= ring said Enum in a background worker context without having to use PHP `se= rialize()` function and store PHP-specific dialect in a database that is us= ed 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 Ba= sic Enum, which could make it less contentious. Also, in the spirit of NOT = making Enums "Fancy strings", I'm looking for ways to reconst= ruct my Enum and all the behaviors available inside of it without even havi= ng to associate or think about a string. The only reason a string comes int= o the discussion is because $enum->value is one and is stored. I also ch= ecked and:

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

is a parse error. [= 6].

Larry has also suggested that instead of makin= g Basic Enum implement `::from()` and `::tryFrom()` we could instead offer = auto-populated String-Backed Enum values. That means transforming this:

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

(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 'B= az';
}

I also like this proposal. Although = semantically, I think it would be better / have been better to have Basic E= num implementing the ::from() methods, one could argue that adding it now c= ould be a breaking change since people could have Basic Enum already implem= enting their own custom ::from() method.

In conclu= sion, 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 t= hat mindset. However, PHP is highly used in Web context where we may need t= o 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 ca= n 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-Bac= ked Enums at all.=C2=A0

Where casing is concerned = (camelCase, PascalCase, snake-case, etc) [7], one can argue that if you wan= t 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 t= o the enum name is that it doesn't matter if I follow PER-CS rules or n= ot, 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 agai= nst everything I shared to see if there are any flaws in my thought process= .


--
Marco Deleu
--000000000000d54f4506397f12b5--