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

- Thread: https://externals.io/message/129698
- Original archive: https://news-web.php.net/php.internals/129698
- Started by Jordi Kroon on 2025-12-27T15:26:32+00:00
- Messages: 4
- Reply by email to internals@lists.php.net
- More for agents: search with https://externals.io/search.md?q={query} · JSON API at https://externals.io/api · documentation at https://externals.io/llms.txt

---

## #129698 — Jordi Kroon — 2025-12-27T15:26:32+00:00

URL: https://externals.io/message/129698#129698

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

---

## #129699 — Jordi Kroon — 2025-12-27T15:46:58+00:00

URL: https://externals.io/message/129698#129699 · In reply to: #129698

> 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.

---

## #129701 — Ben Ramsey — 2025-12-27T18:26:10+00:00

URL: https://externals.io/message/129698#129701 · In reply to: #129699

> 
> > […]
> return.
> > […]
> 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

---

## #129703 — Jakub Zelenka — 2025-12-27T21:06:20+00:00

URL: https://externals.io/message/129698#129703 · In reply to: #129698

Hi,



> 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
