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

From: Date: Sat, 27 Dec 2025 15:26:32 +0000
Subject: [RFC Idea] Generic Collection Notation for Iterables (array<T>)
Groups: php.internals 
Request: Send a blank email to internals+get-129698@lists.php.net to get a copy of this message
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**
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>
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.
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**
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

« previous php.internals (#129698) next »