Re: [RFC Idea] Generic Collection Notation for Iterables (array<T>)

From: Date: Sat, 27 Dec 2025 18:26:10 +0000
Subject: Re: [RFC Idea] Generic Collection Notation for Iterables (array<T>)
References: 1 2  Groups: php.internals 
Request: Send a blank email to internals+get-129701@lists.php.net to get a copy of this message
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 > > { > > /** > > * @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

« previous php.internals (#129701) next »