On Tue, May 12, 2026 at 5:20 PM Ondřej Mirtes <[email protected]> wrote:
> On 10. 5. 2026 at 21:02:32, Seifeddine Gmati <[email protected]> > wrote: > >> Hello Internals, >> >> I'd like to start the discussion on a new RFC adding bound-erased >> generics types to PHP. >> >> Generic type parameters can be declared on classes, interfaces, >> traits, functions, methods, closures, and arrow functions, with >> bounds, defaults, and variance markers. Type parameters erase to their >> bound at runtime; the pre-erasure form is preserved for Reflection and >> consumed by static analyzers. >> >> - RFC: https://wiki.php.net/rfc/bound_erased_generic_types >> - Implementation: https://github.com/php/php-src/pull/21969 >> >> Thanks, >> Seifeddine. >> > > Hi, PHPStan creator and maintainer here. I like this RFC, especially the > depth at which it explains why a substantial portion of PHP developers > would welcome this addition to the language. > > Some people here and on other channels voiced their concerns about types > not being enforced at runtime. My view is that this RFC is for an audience > that has been experiencing this every day already while developing in PHP > for many years. Because the PHP type system is currently insufficient in > expressing types, we use generics in PHPDocs for this job. And they don’t > mean anything for the runtime. But we make sure to run static analysers to > check our code. > > This RFC will make the experience of developing in PHP nicer for this > audience. I’d compare it to Constructor Property Promotion RFC which > reduced the need to mention the same property name in code from 4 to 1. > > Today if we want to accept a generic object in a parameter, we have to > write it like this: > > /** > * @param Collection<Foo> $collection > */ > function doFoo(Collection $collection): void > { > } > > So the parameter name and the class name have to be repeated. > > In this RFC the code above instead becomes this: > > function doFoo(Collection<Foo> $collection): void > { > } > I think my biggest reservation which I'm sure is the same for plenty of others who've read the propsoal is that I can define doFoo there and yet still do $barCollection = new Collection($barList); // Collection<Bar> doFoo($barCollection); And the only way that will be caught is by static analysis. Erased generics in Java are fine, because there is a mandatory compilation process that will check and enforce the types. Erased generics in Python is fine, because there is no type checking *at all* and interpreting the standard syntax for type information is explicitly left to community tooling. PHP is in a weird middle ground. It has no mandatory static check prior to execution but it *does* do runtime type checking, *everywhere else* type declarations are used. But not here, not all the time, if this RFC passes. The very presence of generic types in the language syntax will suggest to users (particularly those who aren't already using annotations, Psalm, PHPStan, etc.) that the syntax *means* something, more than effectively an inline comment, in a way that is not true of Python and I think Rowan's got a solid point about how that reach impacts more than "the people who use SA tools today." But even more confusingly, these type declarations will be partially used in inheritance and reflection. So we can reflect the pre-erasure types, but can't conduct an instanceof check. We can't violate bound generic types via inheritance without a TypeError, but we can otherwise invoke a function with a violating type. So it *looks* like PHP can enforce or at least meaningfully understand Collection<Foo> as a runtime type. But the runtime check is still just Collection. The syntax moves generics out of comments and third party tooling while the validation model will still largely remain in that world. I want to want this, I want this syntax to be part of PHP in a very real way, but given how much members of the PHP community have been beating the drum for generics for years, is it right to deliver a chimera version of it as the long term solution? It's not me who needs to be persuaded in either direction, just food for thought. I like it and I don't at the same time. > > Without making things worse for anyone. But making it better for the > audience who has been using generics with no runtime enforcement for many > years. Which version would you rather write? Prior art in other languages > is the proof this makes sense. > > Let’s say this RFC passes and is released in the next PHP version. If I > don’t use static analysers today and a library I depend on introduces > native generics, nothing changes for me. Same way I violated @template > PHPDocs before, now I’m violating native generics instead. > > If someone uses @template PHPDocs today in their own code, you can assume > they almost certainly also runs a static analyser. No one is forcing anyone > to adopt all language features. Same way the match expression isn’t for > everyone, bound-erased generic types don’t have to be for everyone. > > But there are many PHP developers who would welcome this and have been > beating the drum for many years. The PHP documentation about this feature > could mention the compromises needed to deliver this anticipated feature. > And if someone misuses that (introduces generics in their code without > checking with static analyser), well, that's a bug they've introduced — the > same class of bug already possible today with @template. > > Ondřej Mirtes > >
