Newsgroups: php.internals Path: news.php.net Xref: news.php.net php.internals:129701 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 A40051A00BC for ; Sat, 27 Dec 2025 18:26:33 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=php.net; s=mail; t=1766859998; bh=9g3HpMIzVYF1ThLSRuuSIQVv0sSFMPnfEokUeWDhjrQ=; h=References:In-Reply-To:From:Date:Subject:To:Cc:From; b=jI5VtpH+MIeKVVCRDh1Z4N93PIhV/iHv1xGn5vPvxomeqyi5fxQ7O48JLN8LQVaJE pd3ri6xD+j18tX4C0D6I9IbquP0sC5l/ps8Tw28FAcV22D+TtBXGPuE75peO8vafP9 FVDo2uU9afp2ee2uN2cO2RLYt5QDXY3x3/VUYb7J9AkMCDadH3tJjuFifn+QjP+Dpd U+ZCQnRL6HHni0FYSzi3w7opCng4q7coBHNkOx7bgh4s9ggsayQfUL+cdVlQjF6jny EwOkT7nu3GMc5c+XQsW3q78bdHaS+fClhwMU8LJxJQVmmvI5yGqlYEqCRmaDNPzSOK M/du9IvL8ErTg== Received: from php-smtp4.php.net (localhost [127.0.0.1]) by php-smtp4.php.net (Postfix) with ESMTP id 44D3A18004C for ; Sat, 27 Dec 2025 18:26:37 +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.6 required=5.0 tests=BAYES_50,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,DKIM_VALID_EF,DMARC_PASS,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: No X-Envelope-From: Received: from mail-yx1-f52.google.com (mail-yx1-f52.google.com [74.125.224.52]) (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 ; Sat, 27 Dec 2025 18:26:26 +0000 (UTC) Received: by mail-yx1-f52.google.com with SMTP id 956f58d0204a3-6432842cafdso7025908d50.2 for ; Sat, 27 Dec 2025 10:26:21 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=benramsey.com; s=google; t=1766859981; x=1767464781; 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=xDwfldKG4j4hwVPMvuNYyknJ7m2yUv3+6ibLLZrfqbs=; b=fMtHaRdQS/QT3AxwIQ4ukZDTVG3/0mBj+2Uu8OyzI5+RYrWA8Y99kBurqloPPm2P14 gd8jlyAJmRWBLbEeU/jLBj8CmQ5fAAay+ne6bccIIYdIeQMyCQmwAWqGqY1uJNKXUhPm UajhdqFc0q4z2Owz9Nyv7A4jWSBKjKhprDKAML62XjJW/40yN0KfPmy+p2FwcttuY1Fw rsNrGfq3ylRBPLaT3sWzTiuiexH2s6I65jloNK2skaxR/tlbJuEHYIBmfiPJRUeSqmzB sMdPCNIWNoUb+sjVmZOWHnhPNmFM7EtpQ6K63n6ZWSce10O28fYwU6N+RfedE+IDNq2u DSGQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1766859981; x=1767464781; 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=xDwfldKG4j4hwVPMvuNYyknJ7m2yUv3+6ibLLZrfqbs=; b=OM3MtrIrKLJlh3ygsrSAqPmOqqSUqDMC4l34T8xUF+ZN93z8qsj+ojZbLuhnAfvVD2 uyB+gpADaB3iU+VZ9gBSh0KdIhq1RR1g68/plGXOvMcH46Mx/bijbxehYBlrZDn3hFgK Gfv3jcP8aq4dWRt3E0ExWWWsh9yK/VKt5XTsimlC564GksJKXy15xKG2Vm1K4G0H4G1l a3fAWEbW+kghp51lRpkZjbtFGjQpFvILkCl8J0r3WbDXR2GhIKLGDOnQWjh6EFqaEyR1 GEksEA0GGoOjUKlE5xcuS1u17aVwEE9p8KBdl3/gQx2v0vUVdyCFsrFooskJ3IKnqGb0 eg8g== X-Gm-Message-State: AOJu0Yw+fDzhEg/uULpm3oabCP4cmyw7n6P3bqpZC8qjO1vMgtKjrkED 0SAr1w9koeia9B+Ch7nzzu07SPfO9dreZ0VuCHck1xVIQghu3Pvt76FMeqlXu0o8yyrA5SNlOYw qzRwMEy4MA4ktgwG9opZPCIcda/9jYFttJ74zD6r9 X-Gm-Gg: AY/fxX4XCAz93ISJyVBW4308R5lYBkD+D+oZUxW5jVaDnL515A79oGE9AIS4YPzz84l WNlSU9CZ2ZfjSwkxcWwKV8+PmhI09t/7rrZMUwi9n4GbVNi35CEF59Hajl9JDgqOhZrcaONwPtk J2DMAWpsJuS/19F/DLikD22p5YuiaF+JDRF2aouvvPhumVOukHkbfk9jvgQpl2GUhXEHXCNBLcs FKXqcwDnCQSxbVBdcwqiYXHkdzWNmStWRt2it/QbUlBvso1iKVyVqFXSGaNheeTd2EtQQg= X-Google-Smtp-Source: AGHT+IH3x59HbNpDiPiIVyxloPD+Difan/Opm2RoNme9KLw9AKjsTqzdrNztXSylM0JaePqTvTfVlPVbv3zBJzgRB1A= X-Received: by 2002:a53:9e8c:0:b0:644:77d5:a0d7 with SMTP id 956f58d0204a3-6466a8dd48fmr15660369d50.73.1766859981239; Sat, 27 Dec 2025 10:26:21 -0800 (PST) Precedence: list list-help: list-unsubscribe: list-post: List-Id: x-ms-reactions: disallow MIME-Version: 1.0 References: <20251227152633.7EC311A00BD@lists.php.net> <20251227154659.39FDB1A00BD@lists.php.net> In-Reply-To: <20251227154659.39FDB1A00BD@lists.php.net> Date: Sat, 27 Dec 2025 12:26:10 -0600 X-Gm-Features: AQt7F2r_Vp4FNZk0xrdk5pDnTtqSF9lzWGF6NMfC_rZnRUQa_6-vtgsLj1R3SFQ Message-ID: Subject: Re: [PHP-DEV] [RFC Idea] Generic Collection Notation for Iterables (array) To: Jordi Kroon Cc: internals@lists.php.net Content-Type: multipart/alternative; boundary="0000000000008cc5730646f325a9" From: ben@benramsey.com (Ben Ramsey) --0000000000008cc5730646f325a9 Content-Type: text/plain; charset="UTF-8" On Sat, Dec 27, 2025 at 09:49 Jordi Kroon wrote: > On 27/12/2025 4:26 pm, Jordi Kroon wrote: > > Hi everyone, > > > > I would like to propose a new type in PHP: Generic Collection Notation > > for Iterables (`array`). > > > > **The problem** > > PHP provides several ways to represent sequences of values: > > > > - `array` > > - `iterable` > > - `Traversable` implementations > > - `generators` > > > > While these constructs are fundamental to PHP, none of them allow the > > developer to express **what type of values they yield or contain** at > > the language level. > > > > > > This leads to several issues: > > - Static analysis relies heavily on PHPDoc annotations. > > - Runtime type hints communicate structure but not intent. > > - APIs lack self descriptive type information. > > - Developers must duplicate type information across signatures and > > documentation. > > > > **Example** > > ```php > > class UserService > > { > > /** > > * @return User[] > > */ > > public function getAllUsers(): array > > { > > return [new User("Alice"), new User("Bob")]; > > } > > > > /** > > * @param User $user > > * @param Role[] $roles > > * @return void > > */ > > public function saveRoles($user, array $roles): void > > { > > // Some database call > > } > > } > > ``` > > > > **The proposal** > > Introduce parameterized iterable types using generic like syntax: > > `array` > > `iterable` > > `Traversable` > > `Generator` > > > > ```php > > function processUsers(array $users): void { } > > > > function normalize(array $values): array { } > > ``` > > > > Optionally we could also extend the new array syntax with this > > functionality. > > > > ```php > > function processUsers(User[] $users): void { } > > > > function normalize(string[] $values): string[] { } > > ``` > > > > Key points: > > - The existing `array` type remains valid and unchanged. > > - `array` means an array whose elements are of type `T`. > > - The syntax is currently invalid in PHP and therefore does not > > introduce a backward compatibility break. > > > > **Example** > > ```php > > class UserService > > { > > public function getAllUsers(): array > > { > > return [new User("Alice"), new User("Bob")]; > > } > > > > public function saveRoles(User $user, array $roles): void > > { > > // Some database call > > } > > > > public function streamAllUsers(): Generator > > { > > yield new User("Alice"); > > yield new User("Bob"); > > } > > > > public function iterateAllUsers(): ArrayIterator > > { > > return new ArrayIterator([new User("Alice"), new User("Bob")]); > > } > > > > public function getUserProvider(): Traversable > > { > > return new ArrayIterator([new User("Alice"), new User("Bob")]); > > } > > > > public function normalizeNames(iterable $names): > > iterable > > { > > foreach ($names as $name) { > > yield trim($name); > > } > > } > > } > > ``` > > > > **Runtime semantics and enforcement** > > The goal is that `array` and related iterable parameterizations > > behave like other PHP types: if a value is passed or returned that > > violates the declared type, a `TypeError` is thrown. > > > > The main question is when and how enforcement occurs for eager versus > > lazy containers. > > - Checked on function argument receive, property assignment, and > return. > > - Each element value is validated against `T`. > > There are two approaches, but only one gives strong runtime guarantees. > > > > Preferred behavior: > > - Validate on consumption when the iterable is iterated. > > - If a yielded element violates `T`, throw `TypeError` at the point > > of iteration. > > > > This mirrors the fact that `iterable` may be lazy and cannot be fully > > validated up front. > > > > **Implementation** > > I have basic C knowledge but I don't have much experience with Zend > > Engine / PHP Core. However I am fully committed to: > > - Write and maintain the RFC document. > > - Test and write tests for the implementation or draft > > - Participate in discussions > > - Collaborate with anyone willing to help with the implementation > > > > **Keys and additional parameters** > > This proposal focuses on element types. Keys are intentionally out of > > scope for the initial version. > > > > Possible follow up work could explore `array` and > > `Generator`. > > > > **Next steps** > > - I would like to have hear any potential caveats. For example > > regarding lazy loading. > > - If the RFC gains internal support, I will officially publish the > > first initial draft of the RFC. > > - Whether supporting the shorthand `T[]` should be part of the initial > > scope or a follow up > > - Whether supporting `TKey` should be part of the initial scope or a > > follow up > > > > Kind regards, > > Jordi Kroon > Yes, I am fully aware https://wiki.php.net/rfc/generic-arrays exists. > But since it's older date I was not sure if I had to revive the original > or start a new. That said since PHP is becoming a more strict language, > it became more relevant. And the original RFC doesn't mention anything > regarding Traversables or other iterables. Though I would like to give > my sincere for the work that has been done for the current RFC proposal. I recommend reading this blog post from August that takes an in-depth look at the problem and potential solutions: https://thephp.foundation/blog/2025/08/05/compile-generics/ Another relevant post is from August 2024, a year before the one linked above: https://thephp.foundation/blog/2024/08/19/state-of-generics-and-collections/ Cheers, Ben --0000000000008cc5730646f325a9 Content-Type: text/html; charset="UTF-8" Content-Transfer-Encoding: quoted-printable
On Sat, Dec 27, 2025 at 09:49 Jordi Kroon <jordikroon@me.com> wrote:
On 27/12/2025 4:26 pm, Jordi Kroon wrote:
> Hi everyone,
>
> I would like to propose a new type in PHP: Generic Collection Notation=
> for Iterables (`array<T>`).
>
> **The problem**
> PHP provides several ways to represent sequences of values:
>
> - `array`
> - `iterable`
> - `Traversable` implementations
> - `generators`
>
> While these constructs are fundamental to PHP, none of them allow the =
> developer to express **what type of values they yield or contain** at =
> the language level.
>
>
> This leads to several issues:
> - Static analysis relies heavily on PHPDoc annotations.
> - Runtime type hints communicate structure but not intent.
> - APIs lack self descriptive type information.
> - Developers must duplicate type information across signatures and > documentation.
>
> **Example**
> ```php
> class UserService
> {
>=C2=A0 =C2=A0=C2=A0=C2=A0 /**
>=C2=A0 =C2=A0=C2=A0=C2=A0=C2=A0 * @return User[]
>=C2=A0 =C2=A0=C2=A0=C2=A0=C2=A0 */
>=C2=A0 =C2=A0=C2=A0=C2=A0 public function getAllUsers(): array
>=C2=A0 =C2=A0=C2=A0=C2=A0 {
>=C2=A0 =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 return [new User(&quo= t;Alice"), new User("Bob")];
>=C2=A0 =C2=A0=C2=A0=C2=A0 }
>
>=C2=A0 =C2=A0=C2=A0=C2=A0 /**
>=C2=A0 =C2=A0=C2=A0=C2=A0=C2=A0 * @param User $user
>=C2=A0 =C2=A0=C2=A0=C2=A0=C2=A0 * @param Role[] $roles
>=C2=A0 =C2=A0=C2=A0=C2=A0=C2=A0 * @return void
>=C2=A0 =C2=A0=C2=A0=C2=A0=C2=A0 */
>=C2=A0 =C2=A0=C2=A0=C2=A0 public function saveRoles($user, array $roles= ): void
>=C2=A0 =C2=A0=C2=A0=C2=A0 {
>=C2=A0 =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 // Some database call=
>=C2=A0 =C2=A0=C2=A0=C2=A0 }
> }
> ```
>
> **The proposal**
> Introduce parameterized iterable types using generic like syntax:
> `array<T>`
> `iterable<T>`
> `Traversable<T>`
> `Generator<T>`
>
> ```php
> function processUsers(array<User> $users): void { }
>
> function normalize(array<string> $values): array<string> {= }
> ```
>
> Optionally we could also extend the new array syntax with this
> functionality.
>
> ```php
> function processUsers(User[] $users): void { }
>
> function normalize(string[] $values): string[] { }
> ```
>
> Key points:
>=C2=A0 =C2=A0- The existing `array` type remains valid and unchanged. >=C2=A0 =C2=A0- `array<T>` means an array whose elements are of ty= pe `T`.
>=C2=A0 =C2=A0- The syntax is currently invalid in PHP and therefore doe= s not
> introduce a backward compatibility break.
>
> **Example**
> ```php
> class UserService
> {
>=C2=A0 =C2=A0=C2=A0=C2=A0 public function getAllUsers(): array<User&= gt;
>=C2=A0 =C2=A0=C2=A0=C2=A0 {
>=C2=A0 =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 return [new User(&quo= t;Alice"), new User("Bob")];
>=C2=A0 =C2=A0=C2=A0=C2=A0 }
>
>=C2=A0 =C2=A0=C2=A0=C2=A0 public function saveRoles(User $user, array&l= t;Role> $roles): void
>=C2=A0 =C2=A0=C2=A0=C2=A0 {
>=C2=A0 =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 // Some database call=
>=C2=A0 =C2=A0=C2=A0=C2=A0 }
>
>=C2=A0 =C2=A0=C2=A0=C2=A0 public function streamAllUsers(): Generator&l= t;User>
>=C2=A0 =C2=A0=C2=A0=C2=A0 {
>=C2=A0 =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 yield new User("= Alice");
>=C2=A0 =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 yield new User("= Bob");
>=C2=A0 =C2=A0=C2=A0=C2=A0 }
>
>=C2=A0 =C2=A0=C2=A0=C2=A0 public function iterateAllUsers(): ArrayItera= tor<User>
>=C2=A0 =C2=A0=C2=A0=C2=A0 {
>=C2=A0 =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 return new ArrayItera= tor([new User("Alice"), new User("Bob")]);
>=C2=A0 =C2=A0=C2=A0=C2=A0 }
>
>=C2=A0 =C2=A0=C2=A0=C2=A0 public function getUserProvider(): Traversabl= e<User>
>=C2=A0 =C2=A0=C2=A0=C2=A0 {
>=C2=A0 =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 return new ArrayItera= tor([new User("Alice"), new User("Bob")]);
>=C2=A0 =C2=A0=C2=A0=C2=A0 }
>
>=C2=A0 =C2=A0=C2=A0=C2=A0 public function normalizeNames(iterable<st= ring> $names):
> iterable<string>
>=C2=A0 =C2=A0=C2=A0=C2=A0 {
>=C2=A0 =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 foreach ($names as $n= ame) {
>=C2=A0 =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2= =A0 yield trim($name);
>=C2=A0 =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 }
>=C2=A0 =C2=A0=C2=A0=C2=A0 }
> }
> ```
>
> **Runtime semantics and enforcement**
> The goal is that=C2=A0 `array<T>`=C2=A0 and related iterable par= ameterizations
> behave like other PHP types: if a value is passed or returned that > violates the declared type, a=C2=A0 `TypeError`=C2=A0 is thrown.
>
> The main question is when and how enforcement occurs for eager versus =
> lazy containers.
> -=C2=A0=C2=A0 Checked on function argument receive, property assignmen= t, and return.
> -=C2=A0=C2=A0 Each element value is validated against=C2=A0 `T`.
> There are two approaches, but only one gives strong runtime guarantees= .
>
> Preferred behavior:
> -=C2=A0=C2=A0 Validate on consumption when the iterable is iterated. > -=C2=A0=C2=A0 If a yielded element violates=C2=A0 `T`, throw=C2=A0 `Ty= peError`=C2=A0 at the point
> of iteration.
>
> This mirrors the fact that=C2=A0 `iterable`=C2=A0 may be lazy and cann= ot be fully
> validated up front.
>
> **Implementation**
> I have basic C knowledge but I don't have much experience with Zen= d
> Engine / PHP Core. However I am fully committed to:
>=C2=A0 =C2=A0- Write and maintain the RFC document.
>=C2=A0 =C2=A0- Test and write tests for the implementation or draft
>=C2=A0 =C2=A0- Participate in discussions
> - Collaborate with anyone willing to help with the implementation
>
> **Keys and additional parameters**
> This proposal focuses on element types. Keys are intentionally out of =
> scope for the initial version.
>
> Possible follow up work could explore=C2=A0 `array<TKey, TValue>= `=C2=A0 and
> `Generator<TKey, TValue>`.
>
> **Next steps**
>=C2=A0 =C2=A0- I would like to have hear any potential caveats. For exa= mple
> regarding lazy loading.
>=C2=A0 =C2=A0- If the RFC gains internal support, I will officially pub= lish the
> first initial draft of the RFC.
>=C2=A0 =C2=A0- Whether supporting the shorthand `T[]` should be part of= the initial
> scope or a follow up
>=C2=A0 =C2=A0- Whether supporting `TKey` should be part of the initial = scope or a
> follow up
>
> Kind regards,
> Jordi Kroon
Yes, I am fully aware https://wiki.php.net/rfc/generic-arrays= exists.
But since it's older date I was not sure if I had to revive the origina= l
or start a new. That said since PHP is becoming a more strict language, it became more relevant. And the original RFC doesn't mention anything =
regarding Traversables or other iterables. Though I would like to give
my sincere for the work that has been done for the current RFC proposal.

I recommend reading= this blog post from August that takes an in-depth look at the problem and = potential solutions:=C2=A0https://thephp.foundatio= n/blog/2025/08/05/compile-generics/

Another relevant post is from August 2024, a year before t= he one linked above:=C2=A0

Chee= rs,
Ben

--0000000000008cc5730646f325a9--