Le sam. 16 mai 2026 à 03:21, Seifeddine Gmati <[email protected]> a écrit :
> Hi Nicolas, > > The "SA tools drop legacy docblock support immediately" scenario isn't > going to happen on the timeline you're worried about. What's more > likely is a multi-year deprecation curve: tools will fully support > docblock syntax for years after native generics land, then gradually > stop adding *new* features to the docblock side (e.g., if a future RFC > adds lower bounds or where constraints tools will support it natively > but won't try to retrofit it into docblock syntax), and only after the > ecosystem has clearly moved would full docblock support actually > deprecate. > > I can speak for Mago: we won't drop docblock generic support for at > least several years after native generics ship, because we need to > keep supporting PHP versions earlier than the one this RFC lands in > anyway. PHPStan and Psalm are in the same position: they each support > a wide range of PHP versions. Dropping docblock generics would mean > cutting off users on those older versions entirely, which I presume > none of the maintainers want to do. > > The timeline math also helps. If this RFC ships in PHP 8.6, Symfony > 9.1 in May 2028 would be the natural place to bump the minimum to 8.6, > that's two years from now. And SA tools would most likely support > docblock generics for even longer. the long-tail > Symfony/Laravel/Doctrine projects would already be on PHP versions > that support native syntax, and the migration would be available > rather than required. > > The concern that contributor pull requests adding native generics > before the project is ready will put pressure on maintainers is real, > but it mirrors the shape of every previous PHP feature. Readonly > properties, enums, named arguments, FCCs, etc. all of these created > the same dynamic, which frameworks worked out using version > constraints (`composer.json` `"php": ">=8.0"`), conditional code, and > policy decisions about when to bump minimums. Native generics don't > introduce a new shape of problem; they fit the existing one. > > On the preprocessor idea: I think the same concerns that ruled out > userland generics preprocessors in the RFC's "Userland preprocessors" > section apply here. Composer plugins can't reach the IDE, editor, > debugger, profiler, test runner, or CI, the boundaries where > developers actually work. A preprocessor that erases native generics > before execution on older PHP would solve the runtime story but not > the tooling story; SA tools, IDEs, and everything else still see the > native syntax and need to handle it. So even with a userland > preprocessor, projects that want native syntax in source still need > their toolchain to support native generics. > > That said, if Symfony specifically needs a preprocessor that strips > native generics for runtime execution on older PHP versions, I'd > genuinely be willing to write one. Mago already has the parser, the > formatter, and the AST-rewriting infrastructure to make this fairly > straightforward; it's a weekend project, not a research one. Happy to > do it if it actually unblocks adoption for Symfony. Just say the word. > > I don't think this warrants baking adoption concerns into the RFC text > directly. The deprecation curve is going to be slow regardless of what > the RFC says, and writing migration guidance into the RFC pre-commits > to specific timelines that the ecosystem will resolve organically. If > it would be useful, I can write a separate migration-guide blog post > after the RFC settles, but I'd rather not freeze guidance into the > spec Thanks for your answer, it's good to read you understand the challenge that will exist once the RFC lands. I don't know if you're right about the timescale, but let's hope so. At least having this discussion today might help raise the need for LTS of docblock-based SA tools. Due noted for your help about a userland type-eraser when we'll be there :) About the BC break itself, I want to be clear that this is not the syntax that's going to cause a problem. Like you said, Symfony/whatever will bump to 8.6 one day (more likely in November 2027 in v9.0 for Symfony) and that day we'll be able to use the syntax. The BC concern is about adopting native generics without introducing BC breaks. Bob already shared the idea to raise deprecations instead of errors in https://externals.io/message/130816#130845 That might be the wise way forward. I sent you the message below already but missed adding internals in the loop: The RFC's call-site BC story is well designed: "adding generic parameters to a function does not require any caller to change." Existing pick($a, $b) calls keep working after pick gains <L, R>. That's the right design. My remaining concern is about inheritance. Adding a type parameter to a class breaks every subclass that does not supply an argument. The RFC points at defaults as the fix: class Foo<T = mixed> lets class Bar extends Foo {} keep compiling. This is the right tool for libraries that adopt generics with defaults from day one. But libraries with strict bounds may have no sensible default: class Foo<T : SomeInterface> cannot default to mixed, and there is no wildcard for "any class implementing SomeInterface". These libraries have no migration path that does not break every subclass at compile time. The ecosystem will pay this cost one library at a time and this will slow down adoption by a lot. I'd like to suggest adding a deprecation window for missing inheritance arguments, independent of defaults. Concretely: for PHP version 8.x, class Bar extends Foo {} against a class Foo<T> without a default emits E_DEPRECATED and behaves as if T was substituted by its bound, rather than failing at compile time. Then PHP v9.0 makes it a hard error. This turns "hard BC breaks ahead" into "guided migration". This is how PHP already did for most other type-system changes: return types added step by step, nullable parameters, implicit nullability deprecation, dynamic properties. The pattern is familiar and the ecosystem knows how to deal with it. It's the same shape as the turbofish optionality already in the RFC: adding <T> to a function would not force callers to change. The deprecation window extends this to inheritance sites, which is where BC pressure also lives in the ecosystem. A library that adds <T> to a class today, on a generics-aware PHP version, would emit deprecations on user code that has not yet declared an argument, the way today's @template adopters have always managed this gap. Ppl that do want a hard failure as early as possible could still rely on SA tools of course. Adding generics to a class would become a gradual transition for every consumer, not a forced switch. I think this works with the existing call-site BC story rather than against it. It would help adoption a lot. Cheers, Nicolas
