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.