Hi,
On Sat 27. 12. 2025 at 16:28, Jordi Kroon <[email protected]> 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
>