@@ -663,7 +663,7 @@ $producers->add(new Producer(new Car()));
663663
664664---
665665
666- ## Class Inheritance (` @extends ` , ` @implements ` , and ` @use ` )
666+ ## Class, Interface, & Trait Inheritance (` @extends ` , ` @implements ` , ` @use ` )
667667
668668When a child class extends a generic parent class, implements a generic interface, or uses a generic trait, declare the template mapping using any of the recognized inherited template annotations:
669669
@@ -673,6 +673,8 @@ When a child class extends a generic parent class, implements a generic interfac
673673| ** Interface Implementation** | ` @implements ` , ` @template-implements ` , ` @phpstan-implements ` , ` @psalm-implements ` |
674674| ** Trait Usage** | ` @use ` , ` @template-use ` , ` @phpstan-use ` |
675675
676+ ### 1. Interface Implementation (` @implements ` / ` @template-implements ` )
677+
676678``` php
677679/**
678680 * Generic Interface
@@ -711,6 +713,106 @@ $processor->process(new Dog());
711713// Throws: TypeError: CatProcessor::process(): Argument $item (template T = Cat) must be of type Cat
712714```
713715
716+ ### 2. Class Extension (` @extends ` / ` @template-extends ` )
717+
718+ ``` php
719+ /**
720+ * @template T
721+ */
722+ abstract class BaseRepository
723+ {
724+ /**
725+ * @param T $entity
726+ */
727+ public function save(mixed $entity): void
728+ {
729+ // ...
730+ }
731+ }
732+
733+ /**
734+ * Fulfills T = User via @template-extends
735+ *
736+ * @template-extends BaseRepository<User >
737+ */
738+ class UserRepository extends BaseRepository
739+ {
740+ }
741+
742+ $userRepo = new UserRepository();
743+
744+ // Valid Save
745+ $userRepo->save(new User('Alice'));
746+
747+ // Invalid Save
748+ $userRepo->save(new Product('SKU-100'));
749+ // Throws: TypeError: UserRepository::save(): Argument $entity (template T = User) must be of type User
750+ ```
751+
752+ ### 3. Generic Traits (` @use ` / ` @template-use ` / ` @phpstan-use ` )
753+
754+ When a class uses a generic Trait, declare the template binding either at the ** class level** or ** directly above the inline ` use Trait; ` statement** :
755+
756+ #### Generic Trait Definition (` ItemLoggerTrait.php ` )
757+
758+ ``` php
759+ /**
760+ * @template T
761+ */
762+ trait ItemLoggerTrait
763+ {
764+ /**
765+ * @param T $item
766+ */
767+ public function logItem(mixed $item): bool
768+ {
769+ return true;
770+ }
771+ }
772+ ```
773+
774+ #### Option A: Class-Level Trait Annotation (` @use ` / ` @template-use ` )
775+
776+ ``` php
777+ /**
778+ * Class docblock binds T = Dog for the trait
779+ *
780+ * @use ItemLoggerTrait<Dog >
781+ */
782+ class ClassLevelLogService
783+ {
784+ use ItemLoggerTrait;
785+ }
786+
787+ $service = new ClassLevelLogService();
788+
789+ $service->logItem(new Dog()); // Valid
790+
791+ $service->logItem(new Car());
792+ // Throws: TypeError: Argument $item (template T = Dog) must be of type Dog, Car given
793+ ```
794+
795+ #### Option B: Inline Statement Trait Annotation (` /** @use */ use Trait; ` )
796+
797+ ``` php
798+ class InlineLogService
799+ {
800+ /**
801+ * Inline statement docblock binds T = Dog
802+ *
803+ * @use ItemLoggerTrait<Dog >
804+ */
805+ use ItemLoggerTrait;
806+ }
807+
808+ $service = new InlineLogService();
809+
810+ $service->logItem(new Dog()); // Valid
811+
812+ $service->logItem(new Car());
813+ // Throws: TypeError: Argument $item (template T = Dog) must be of type Dog, Car given
814+ ```
815+
714816---
715817
716818## Real-World Example 1: Generic Collections (` Collection<T> ` )
@@ -994,3 +1096,4 @@ processCovariantConsumer(new Consumer(new Dog()));
9941096processCovariantConsumer(new Consumer(new Car()));
9951097// Throws: TypeError: processCovariantConsumer() expects Consumer<covariant Animal >, but Consumer<Car > was given
9961098```
1099+ ```
0 commit comments