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
