Re: [RFC Idea] Generic Collection Notation for Iterables (array<T>)
| From: | Jakub Zelenka | Date: | Sat, 27 Dec 2025 21:06:20 +0000 |
| Subject: | Re: [RFC Idea] Generic Collection Notation for Iterables (array<T>) | ||
| References: | 1 | Groups: | php.internals |
| Request: | Send a blank email to internals+get-129703@lists.php.net to get a copy of this message | ||
Hi,
On Sat 27. 12. 2025 at 16:28, Jordi Kroon <jordikroon@me.com> 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
This has been discussed in past and we actually talked about it internally
quite recently. IMHO only T[] should be supported to not give partial
generics and disallow nested arrays.
Arnaud described best the possible issues in
https://externals.io/message/125049#125069
.
There is really not much point to do RFC without implementation so you will
probably need to find someone who is willing and capable to implement it.
Kind regards,
Jakub
>