On 11/05/2026 17:25, Seifeddine Gmati wrote:
I think the core premise is empirically testable, and the test has
already run: PHP has had generics in docblocks for a decade, used by
every major framework. If "someone publishes a library with broken
type information and downstream users get surprised by runtime
behavior" were a real failure mode, we would see it today, as Laravel,
Doctrine, Symfony, PSL, and PHPUnit all run on `@template`-annotated
code and are consumed by millions of downstream applications. The
failure mode you describe is the one that would occur most under the
current system, yet it doesn't.
How do you know? There could be packages on Packagist right now,
where the "@template" annotations are completely wrong. The only people
who would notice would be those who use that library AND subject it to
static analysis; and half of them would probably be too lazy to raise a
bug report or PR, and just mark it ignored locally.
The reason it doesn't is that the people who care about generic type
information are the same people who run static analysis. The
intersection of "uses generics" and "doesn't run a static analyzer" is
approximately empty in practice. Native syntax doesn't change that. It
just gives current users a better way to express what they mean.
I think this reasoning is fundamentally flawed. Right now, generic
annotations *only exist* as part of those static analysis tools; so of
course, the people using the annotations are the people using the tools.
What you're proposing is to add syntax to the language itself, which
will be a big headline feature of a new version of PHP, and documented
in the manual on php.net. That is 100% guaranteed to change the audience
for the feature.
- Generic parameter declarations: arity cap, bound conformance,
default-vs-bound, no top-level self-reference, no shadowing.
- Variance soundness: Covariant parameters cannot appear in input
positions, contravariant parameters cannot appear in output positions,
at the declaration site.
- Inheritance: arity at extends/implements/use, bound conformance with
bound-on-bound for forwarded parameters, diamond detection, parametric
LSP into properties/hooks/trait methods/inherited methods.
- Turbofish at runtime: arity and bounds at every call site that
supplies type arguments.
Forgive me if I'm misunderstanding some of the jargon here, but this all
seems fairly inconsequential compared to actually enforcing the generic
type itself.
Given this:
class Foo<T: int|string> { function test(T $in) { ... } }
I think you're saying that I can't write one of these:
$foo = new Foo::<MySpecialNumberObject>;
class Bar<T: MySpecialNumberObject> extends Foo<T> { ... }
But I don't need to, because I can just write this anyway:
$foo = new Foo::<int>;
$foo->test(new MySpecialNumberObject);
If I don't run a static analyser, that will run just fine.
And if I *do* run a static analyser, it could check all the funky things
about diamonds and self-referential bounds as well. I presume existing
implementations already do these checks, even if they're not 100%
consistent between tools?
Finally, on the "broken code published to Packagist" concern: someone
can already publish:
```
/** Map the given array using the provided callable. */
function map(array $array, callable $fn): array {
return [];
}
```
Absolutely, comments can lie. Docblock annotations can also lie - and,
in my experience, frequently do. But right now, PHP's native syntax does
*not* lie - a property marked "private" really is private, a return type
marked "int" really is always an integer, a parameter
marked "SomeObjectType" will only accept an instance of SomeObjectType,
not even a sneaky "null reference"...
This proposal would fundamentally change that - it would introduce
syntax which looks like it's part of the standard, enforced, type
system; but, in many cases, would do absolutely nothing.
Nobody is calling for PHP to ship a precious type system with support for
lifetimes, and const generic parameters to prevent it
(e.g. `function map<'a, I, O, const SIZE: int>(vec<&'a I, SIZE> & ![] $array, fn(&'a I): &'a
O $fn): vec<&'a O, SIZE> & ![]`).
No, but if someone proposed to make that valid PHP syntax, which did
nothing outside of a third-party tool, I would not expect them to get
much support.
I can absolutely see the advantage of standardising third-party generic
annotations or attributes; but I want to reserve first-class syntax for
features that have first-class enforcement.
Regards,
--
Rowan Tommins
[IMSoP]