On Sat, Dec 27, 2025 at 09:49 Jordi Kroon <[email protected]> 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
> > {
> >      /**
> >       * @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<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:
> >   - The existing `array` type remains valid and unchanged.
> >   - `array<T>` 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<User>
> >      {
> >          return [new User("Alice"), new User("Bob")];
> >      }
> >
> >      public function saveRoles(User $user, array<Role> $roles): void
> >      {
> >          // Some database call
> >      }
> >
> >      public function streamAllUsers(): Generator<User>
> >      {
> >          yield new User("Alice");
> >          yield new User("Bob");
> >      }
> >
> >      public function iterateAllUsers(): ArrayIterator<User>
> >      {
> >          return new ArrayIterator([new User("Alice"), new User("Bob")]);
> >      }
> >
> >      public function getUserProvider(): Traversable<User>
> >      {
> >          return new ArrayIterator([new User("Alice"), new User("Bob")]);
> >      }
> >
> >      public function normalizeNames(iterable<string> $names):
> > iterable<string>
> >      {
> >          foreach ($names as $name) {
> >              yield trim($name);
> >          }
> >      }
> > }
> > ```
> >
> > **Runtime semantics and enforcement**
> > The goal is that  `array<T>`  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<TKey, TValue>`  and
> > `Generator<TKey, TValue>`.
> >
> > **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

Reply via email to