Skip to content
PHP News
Search
Declined

Bound-Erased Generic Types

Adds native generic syntax to classes and functions, with bounds, defaults and variance, erased to each parameter's bound at runtime.

Introduce bound-erased generics as outlined in the RFC?

Primary vote · 2/3 majority

7 Yes 19 No 10 abstain 27% approval

This poll has closed.

Variance marker syntax

· 1/2 majority

  • +T / -T (Hack, Scala) 2
  • in T / out T (C#, Kotlin) 24

This poll has closed.

The main vote failed with 7 in favor, 19 against and 10 abstaining, well short of the two-thirds it needed. A second vote chose the variance syntax in case the main vote passed, and in T / out T beat +T / -T by 24 to 2. That result had no effect once the main vote failed. Voting closed on June 28, 2026.

Summary

Generics let you write a class or function once and use it with many types, so a Box<int> holds an int and a Box<User> holds a User. PHP developers already do this in docblocks with @template, and tools like PHPStan and Psalm check those annotations. This RFC from Seifeddine Gmati proposed adding generics to PHP's own syntax. It was declined.

How it looks

final readonly class Box<+T> {
    public function __construct(
        public T $value,
    ) {}

    public function map<U>(callable $fn): Box<U> {
        return new Box(($fn)($this->value));
    }
}

function identity<T>(T $value): T {
    return $value;
}

$greeting = new Box::<string>("hello, world");

Type parameters could go on classes, interfaces, traits, functions, methods, closures and arrow functions. Each one could have:

  • Bounds, like T : Animal, which say what T must be.
  • Defaults, like K = string.
  • Variance markers, +T and -T, which say whether T only comes out of a class or only goes in.

At call sites, you'd pass types with the ::<...> syntax, nicknamed "turbofish." It's always optional, so a library could add generics without forcing any caller to change their code.

What "bound-erased" means

At runtime, Box<int> and Box<string> are the same class. PHP replaces each type parameter with its bound, or with mixed if it has none. That means PHP still checks the bound, but not the exact type you picked.

As a result, some mistakes would slip through at runtime. For example, new Box::<int>("string") would be accepted. Static analysis tools would catch those cases, just as they do with docblocks today. The RFC compares this approach to Java, which has used erased generics since 2004.

A new Reflection API would let tools read generic information straight from PHP instead of parsing comments. Code that doesn't use generics would compile to the same bytecode as it does today.

What it means for existing code

Nothing, since the RFC was declined. Had it passed, nothing would have broken, because all of the new syntax is a parse error today. Your existing @template docblocks would keep working either way.