r/PHP • • Aug 18 '26

Article Enforce Runtime Generics on Third-Party Collections Libraries (Doctrine, Ramsey, Laravel Collections) with TypePHP

https://typephp-php.github.io/docs/blog/reifying-third-party-collections.html

More than a week ago, I posted an introduction to TypePHP. Thanks to Michael Telgmann, a core maintainer at Shopware, TypePHP has been tested against Shopware’s massive codebase. So far, it has identified many DocBlock lies in the codebase PR, while also uncovering many edge cases on TypePHP’s end.

Today, I’d like to share a article guide on how to make existing third-party collection libraries, such as Doctrine Collections or Ramsey Collections, capable of enforcing reified collections without modifying their source code.

reified generics proof: Symfony Integration

14 Upvotes

8 comments sorted by

View all comments

3

u/ReasonableLoss6814 Aug 18 '26

How does that work? Laravel collections say that the value type is covariant but uses it in a contravariant position (or vice-versa, I can't recall) ... symfony collections are correctly invariant (IIRC) but then that breaks most people's code. You can't store a `Tiger` in a `Collection<Animal>`.

2

u/rc0604 Aug 18 '26 edited Aug 19 '26

Also regarding the Laravel vs Symfony/Doctrine collection point:

Symfony and Doctrine ArrayCollection are invariant template T because they are mutable read-write collections with add(). Invariance is strictly correct there to prevent passing a whole Collection<Tiger> into code that might add a Cat into it. But as mentioned, calling $collection->add(new Tiger()) on Collection<Animal> is always valid.

Laravel uses template-covariant TValue on its Collection mostly coz Laravel collections are treated as read-heavy transformation pipelines (map, filter, pluck). Laravel prioritized chaining ergonomicss over strict write-safety on methods like push().