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.

Reply via email to