Newsgroups: php.internals Path: news.php.net Xref: news.php.net php.internals:129127 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 B0F321A00BC for ; Fri, 7 Nov 2025 08:22:38 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=php.net; s=mail; t=1762503763; bh=yIB8TilmMiloAlAsCPwbwzE9gd7NFevC2aZCdCsHDaA=; h=References:In-Reply-To:From:Date:Subject:To:Cc:From; b=bmdwLUstfyMlSu5JOVIXa3VZpuAMkiPlxA4w2DjnsbqiJIuWL4vgl6keAsC4mFw+v HVRe125vgloc7PCJQaWkAdoycEHtl1gso2TMrpdLNDxmYZf3HLYgtiCrcuOyfCKCUz NYWnxORKlw/5ljEqJ6koUBz0ot3rKLmP1ckr5vLNqsR7MOM7sjfk/3Jak59TJekJ9L Cwz45/B9kFUJ2B1o6JCXV4YvAXLsBLHGPfvWsiMidVEEjQPDwQC+dxDxbfmAgI2q7H I6ZwcF3Y5wPROf6+5N7wEkR30+0G9yV9Nt5ByZfXz90cWH9X/INBOqUM5yOzQq3/MA 0yWHfwcXcR7vg== Received: from php-smtp4.php.net (localhost [127.0.0.1]) by php-smtp4.php.net (Postfix) with ESMTP id C6D32180041 for ; Fri, 7 Nov 2025 08:22:38 +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=-2.1 required=5.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,DKIM_VALID_EF,DMARC_PASS,FREEMAIL_FROM, HTML_MESSAGE,RCVD_IN_DNSWL_NONE,RCVD_IN_MSPIKE_H3,RCVD_IN_MSPIKE_WL, SPF_HELO_NONE,T_SPF_TEMPERROR autolearn=no autolearn_force=no version=4.0.1 X-Spam-Virus: No X-Envelope-From: Received: from mail-ej1-f45.google.com (mail-ej1-f45.google.com [209.85.218.45]) (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 ; Fri, 7 Nov 2025 08:22:28 +0000 (UTC) Received: by mail-ej1-f45.google.com with SMTP id a640c23a62f3a-b727f452fffso78618066b.1 for ; Fri, 07 Nov 2025 00:22:23 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20230601; t=1762503742; x=1763108542; 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=1FJWVk0ZnCXY51F2XJj5Hxoj36jXJ1uMjcr6IvcqqIg=; b=WzwSF/GLqjCyzQyiB9ybFLFHxg5i0e/ah1KeicTbdjAJGVc7iSG/c7VU+HvT8vDWTZ 8cWbsz9IwKLopoTp/9iQjK8hP4eSM/rzl5Ms5xIslJG+sDqSBRkhrh5PxIhQbtaCldcY vE6avJLrzsxhJ8iHua+1+osK9EW/n09u1rug1EeB4G2Rfu9IRPpVmX04eWyLSJlLPHKd pcVioap6dg6RzwFNmnZxLH29Gk50bUmYy3x4cl9DWkb0Em6kSexmgwqVVNgnNng/RH3S FvFXEVCNXO+h6rPPKlgbsBIBN4+z0/6Py7Vh3znsE6xLma4if2TnSkJU+XImbEwGxrmb iMGQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1762503742; x=1763108542; h=cc:to:subject:message-id:date:from:in-reply-to:references :mime-version:x-gm-gg:x-gm-message-state:from:to:cc:subject:date :message-id:reply-to; bh=1FJWVk0ZnCXY51F2XJj5Hxoj36jXJ1uMjcr6IvcqqIg=; b=rdSWCPUAKBD/w+BSHfrmorn0vS0N5sCbZZ4qnDDh8BTWiEkHQli8FC2UsiqWqbUaxx fLG2CEqkWU75VADkxV8fg141NM0maA94bZlEZEsbx7Q0+47XdaedOCLCWHzqORvh/Xea /C/+2CaXHKRfPY96XIcR+8+HUBR1PKQRKXOwymcJ9SoKhnJln2G69ssLnGscKs/qp43c 0V+a7YgAfBQs/9PVc7ZZT4Weuf/42a8rRLv8lzshk5qFZZE+vqy1WuKfZ4oTVkK1asFR y/UAtM5FM54yUTsKabF3HkLZcUXkrHoqF/3/ndZ9GZSI2JIB79og57wDNhYYeiVNU89c +Gyg== X-Forwarded-Encrypted: i=1; AJvYcCVvZWvUIrSDXSlXom+EBhMmwaNEmfX7Uvy0SXsvkl5eNu3nm5I67TD7a1iIoeuXjVIs1Xl0MmoXghk=@lists.php.net X-Gm-Message-State: AOJu0YzZ7pec5X6MoPE/cAIBBhVB7ir/RzsmSh0fS883EUwWNORBCSK2 EUwhjra3rVKSkIlAKoOCNcviPO5dIq2rOnwPzlvV0JD2x0M+CVyego93ZP9zMvK8IxtxioP/mfP ckwSIOqL7Qxo+NBFSj5+Y46o1Ts78OXg= X-Gm-Gg: ASbGncu+mMzGIPOnmdsYD2UTFgrWz/l6Zz3zQdxrXXmkuBmwfIVAGKD3HKyRWn2iBwz PZZVCEvHpyaZdorQa9d63ILvscpOolC9FW4vYd/y6PdvaGYOPNv9Lw6DedkOtII803whKeELOJ5 rBTB2W4rUTi2SdkNSTbTcrpAgDIVLSyJI3fNSIzfRnVu7IVCSqXK7rm9Y4sY+5mZdxo8vq3sZjV WB5R9OmPBoeFlTSvnYRqRWjSDRVxs6VKzlwgZVExKhsoEyt8MSP3DUtEi/rXA== X-Google-Smtp-Source: AGHT+IEmEJ+pVnjnvP8eCgy3axCmK9Pk9UwHm6n0hcXU7luWJbEt4DHUWTpm87BSB8Yp058oaE3IlUgzT8h5YR2YBxw= X-Received: by 2002:a17:907:d17:b0:b70:b9fe:aa56 with SMTP id a640c23a62f3a-b72d0a9d7e4mr81855466b.20.1762503741960; Fri, 07 Nov 2025 00:22:21 -0800 (PST) Precedence: list list-help: list-unsubscribe: list-post: List-Id: x-ms-reactions: disallow MIME-Version: 1.0 References: In-Reply-To: Date: Fri, 7 Nov 2025 11:22:10 +0300 X-Gm-Features: AWmQ_bnZwVEzvjwPtuzJ1fYo7zepaub30Svbu9_88zBxwl21SvUg2Vxw01XvWyY Message-ID: Subject: Re: [PHP-DEV] [RFC] [Discussion] BackedEnum::values() - Seeking feedback before formal RFC To: Valentin Udaltsov Cc: Larry Garfield , php internals Content-Type: multipart/alternative; boundary="0000000000007476620642fce1ec" From: mikhail.d.savin@gmail.com (Mikhail Savin) --0000000000007476620642fce1ec Content-Type: text/plain; charset="UTF-8" Content-Transfer-Encoding: quoted-printable =D0=BF=D1=82, 7 =D0=BD=D0=BE=D1=8F=D0=B1. 2025=E2=80=AF=D0=B3. =D0=B2 07:53= , Mikhail Savin : > > > =D0=BF=D1=82, 7 =D0=BD=D0=BE=D1=8F=D0=B1. 2025=E2=80=AF=D0=B3. =D0=B2 07:= 08, Valentin Udaltsov < > udaltsov.valentin@gmail.com>: > >> =D1=87=D1=82, 6 =D0=BD=D0=BE=D1=8F=D0=B1. 2025=E2=80=AF=D0=B3., 19:30 La= rry Garfield : >> >>> On Wed, Nov 5, 2025, at 10:09 PM, Mikhail Savin wrote: >>> > Hi internals, >>> > >>> > I would like to propose adding a native values() method to the >>> BackedEnum >>> > interface that returns an array of all backing values. Before creatin= g >>> a >>> > formal RFC, I'm seeking feedback on the concept and approach. >>> > >>> > =3D=3D Summary =3D=3D >>> > >>> > The proposal adds: >>> > >>> > interface BackedEnum { >>> > public static function values(): array; >>> > } >>> > >>> > This would allow: >>> > >>> > enum Status: string { >>> > case Active =3D 'active'; >>> > case Inactive =3D 'inactive'; >>> > } >>> > >>> > Status::values(); // ['active', 'inactive'] >>> > >>> > =3D=3D Motivation =3D=3D >>> > >>> > This pattern is extremely common in the wild. Based on GitHub code >>> search: >>> > >>> > * ~3,860+ direct implementations of this exact pattern >>> > * ~20,000-40,000 estimated real usage when accounting for shared >>> traits >>> > * Used in major frameworks: Symfony core (TypeIdentifier.php), >>> > Laravel ecosystem >>> > * Documented by PHP.net: The manual itself shows EnumValuesTrait as >>> > an example >>> >>> Correction: The manual does not show an EnumValuesTrait that I can >>> find. There is a *comment* in the manual that includes this method, bu= t >>> that's not part of the manual proper, and frankly 90% of comments in th= e >>> manual should be removed. (cf: >>> https://www.php.net/manual/en/language.enumerations.traits.php#129250) >>> >>> > Common use cases: >>> > * Database migrations: $table->enum('status', Status::values()) >>> > * Form validation: $validator->rule('status', 'in', Status::values(= )) >>> > * API responses: ['allowed_statuses' =3D> Status::values()] >>> > >>> > =3D=3D Implementation =3D=3D >>> > >>> > I have a working implementation with tests: >>> > https://github.com/php/php-src/pull/20398 >>> > >>> > The implementation: >>> > * Mirrors the existing cases() method structure >>> > * Extracts the value property from each case >>> > * Returns an indexed array (0, 1, 2, ...) >>> > * Only available on BackedEnum, not UnitEnum >>> > * All tests pass >>> >>> I am unclear why this is a major advantage over >>> array_column(Status::cases(), 'value'); >>> >>> > =3D=3D Backward Compatibility - Important Discussion Point =3D=3D >>> > >>> > This is a breaking change. Enums that already define a values() metho= d >>> > will fail with: >>> > >>> > Fatal error: Cannot redeclare BackedEnum::values() >>> > >>> > Based on ecosystem research: >>> > * ~24,000-44,000 enum instances will break >>> > * All implementations are functionally identical to what's being >>> proposed >>> > * Migration is mechanical: just delete the user-defined method >>> >>> This is a hard-stop. There are hundreds of thousands of packages in th= e >>> wild that need to support multiple PHP versions. Nearly all packaglist >>> packages (which I presume is where you're drawing the research from; ei= ther >>> that or GitHub which will give a similar result set) support at least t= wo >>> consecutive versions, if not 4, 5, or 6. >>> >>> A hard break like this would essentially mean the packages containing >>> those 40,000 enums would be unable to support both PHP 8.5 and 8.6 at t= he >>> same time. That's simply not an acceptable impact on the ecosystem, >>> regardless of how nice the feature may or may not be. >>> >>> --Larry Garfield >>> >> >> We could add a virtual $values property. Since enum properties are not >> allowed in userland, it will not break any existing code. >> >> =E2=80=94 >> Valentin >> > > Hi all, > > Thank you for the thoughtful feedback. Based on the discussion so far, th= e > consensus seems to be: "the feature is useful, but the BC break is too > large." > > To address this, I've adjusted the proposal so that user code is allowed > to > redeclare values() on backed enums. This keeps existing projects working > unchanged while providing the native implementation for new code. > > The native values() will only be added when not already defined: > > ```c > if (!zend_hash_exists(&ce->function_table, ZSTR_KNOWN(ZEND_STR_VALUES))= ) > { > ... > } > ``` > > Result: > * Zero BC break - existing code unchanged > * New enums get values() automatically > * Libraries can maintain their implementation for older PHP support > > Trade-off: > I recognize this makes values() the only overridable enum intrinsic > (unlike cases/from/tryFrom). I'll document this clearly and add tests > to lock down the behavior. If needed, we can deprecate user-defined > values() in a later 8.x and make it an error in PHP 9.0. > > Questions: > 1. Is allowing values() override technically acceptable? > 2. Is documenting the inconsistency sufficient? > 3. Should we add deprecation? > 4. Can I submit RFC for this feature? > 5. Should I rather implement it via virtual property, as Valentin > suggested above? > > I updated the PR, and also added a few tests for this behavior. > > Thoughts? > > Best regards, > Savin Mikhail > Hi I am going to create RFC page, cuz badge "Status: requires RFC" was added to PR: https://github.com/php/php-src/pull/20398 Could someone please grant me RFC wiki karma so I can create the page https://wiki.php.net/rfc/add_values_method_to_backed_enum from my account (login - msavin)? --0000000000007476620642fce1ec Content-Type: text/html; charset="UTF-8" Content-Transfer-Encoding: quoted-printable


=D0=BF=D1=82, 7= =D0=BD=D0=BE=D1=8F=D0=B1. 2025=E2=80=AF=D0=B3. =D0=B2 07:53, Mikhail Savin= <mikhail.d.savin@gmail.com= >:


=D0=BF=D1=82, 7 =D0=BD=D0=BE=D1=8F=D0=B1. 2= 025=E2=80=AF=D0=B3. =D0=B2 07:08, Valentin Udaltsov <udaltsov.valentin@gmail.com>:
On Wed, Nov 5, 2025, at 10:09 PM, Mikhail Savin wrote:
> Hi internals,
>
> I would like to propose adding a native values() method to the BackedE= num
> interface that returns an array of all backing values. Before creating= a
> formal RFC, I'm seeking feedback on the concept and approach.
>
> =3D=3D Summary =3D=3D
>
> The proposal adds:
>
>=C2=A0 =C2=A0 =C2=A0interface BackedEnum {
>=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0public static function values(): arra= y;
>=C2=A0 =C2=A0 =C2=A0}
>
> This would allow:
>
>=C2=A0 =C2=A0 =C2=A0enum Status: string {
>=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0case Active =3D 'active';
>=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0case Inactive =3D 'inactive';=
>=C2=A0 =C2=A0 =C2=A0}
>=C2=A0 =C2=A0
>=C2=A0 =C2=A0 =C2=A0Status::values(); // ['active', 'inacti= ve']
>
> =3D=3D Motivation =3D=3D
>
> This pattern is extremely common in the wild. Based on GitHub code sea= rch:
>
>=C2=A0 =C2=A0* ~3,860+ direct implementations of this exact pattern
>=C2=A0 =C2=A0* ~20,000-40,000 estimated real usage when accounting for = shared traits
>=C2=A0 =C2=A0* Used in major frameworks: Symfony core (TypeIdentifier.p= hp),
>=C2=A0 =C2=A0 =C2=A0Laravel ecosystem
>=C2=A0 =C2=A0* Documented by PHP.net: The manual itself shows EnumValue= sTrait as
>=C2=A0 =C2=A0 =C2=A0an example

Correction: The manual does not show an EnumValuesTrait that I can find.=C2= =A0 There is a *comment* in the manual that includes this method, but that&= #39;s not part of the manual proper, and frankly 90% of comments in the man= ual should be removed.=C2=A0 (cf: https://www.php.net/manual/en/language.enumerations.traits.ph= p#129250)

> Common use cases:
>=C2=A0 =C2=A0* Database migrations: $table->enum('status', S= tatus::values())
>=C2=A0 =C2=A0* Form validation: $validator->rule('status', &= #39;in', Status::values())
>=C2=A0 =C2=A0* API responses: ['allowed_statuses' =3D> Statu= s::values()]
>
> =3D=3D Implementation =3D=3D
>
> I have a working implementation with tests:
> https://github.com/php/php-src/pull/20398
>
> The implementation:
>=C2=A0 =C2=A0* Mirrors the existing cases() method structure
>=C2=A0 =C2=A0* Extracts the value property from each case
>=C2=A0 =C2=A0* Returns an indexed array (0, 1, 2, ...)
>=C2=A0 =C2=A0* Only available on BackedEnum, not UnitEnum
>=C2=A0 =C2=A0* All tests pass

I am unclear why this is a major advantage over array_column(Status::cases(= ), 'value');

> =3D=3D Backward Compatibility - Important Discussion Point =3D=3D
>
> This is a breaking change. Enums that already define a values() method=
> will fail with:
>
>=C2=A0 =C2=A0 =C2=A0Fatal error: Cannot redeclare BackedEnum::values()<= br> >
> Based on ecosystem research:
>=C2=A0 =C2=A0* ~24,000-44,000 enum instances will break
>=C2=A0 =C2=A0* All implementations are functionally identical to what&#= 39;s being proposed
>=C2=A0 =C2=A0* Migration is mechanical: just delete the user-defined me= thod

This is a hard-stop.=C2=A0 There are hundreds of thousands of packages in t= he wild that need to support multiple PHP versions.=C2=A0 Nearly all packag= list packages (which I presume is where you're drawing the research fro= m; either that or GitHub which will give a similar result set) support at l= east two consecutive versions, if not 4, 5, or 6.

A hard break like this would essentially mean the packages containing those= 40,000 enums would be unable to support both PHP 8.5 and 8.6 at the same t= ime.=C2=A0 That's simply not an acceptable impact on the ecosystem, reg= ardless of how nice the feature may or may not be.

--Larry Garfield



Hi all,

Thank you for = the thoughtful feedback. Based on the discussion so far, the
consensus = seems to be: "the feature is useful, but the BC break is too large.&qu= ot;

To address this, I've adjusted the proposal so that user cod= e is allowed to
redeclare values() on backed enums. This keeps existing= projects working
unchanged while providing the native implementation f= or new code.

The native values() will only be added when not already= defined:

```c
=C2=A0 if (!zend_hash_exists(&ce->function_= table, ZSTR_KNOWN(ZEND_STR_VALUES))) {

--0000000000007476620642fce1ec--