Generics Workarounds in PHP
debt(d5/e3/b5/t5)
Closest to 'specialist tool catches' (d5). PHPStan and Psalm (listed in detection_hints.tools) catch missing @template annotations, type-unsafe collection returns, and unpropagated type parameters. These are specialist static analysis tools, not default linters or compiler errors — you must explicitly configure and run them.
Closest to 'simple parameterised fix' (e3). The quick_fix indicates adding @template annotations to docblocks is the core fix. However, common_mistakes show you also need to ensure @extends/@implements propagate correctly in subclasses, which can touch multiple related classes. Still largely a pattern replacement within one component rather than cross-cutting refactor.
Closest to 'persistent productivity tax' (b5). Once you adopt PHPDoc generics, every collection/repository class needs consistent @template usage. The applies_to shows this spans all PHP contexts (web, cli, queue-worker). Teams must maintain static analysis in CI, keep annotations in sync with actual types, and new developers must learn the docblock conventions. Not architectural-level burden, but a persistent tax across the codebase.
Closest to 'notable trap' (t5). The misconception states developers believe PHP cannot have type-safe collections without runtime cost — this is a documented gotcha that most PHP devs eventually learn. Common mistakes like forgetting to install PHPStan/Psalm (making @template just comments) or not propagating type parameters to subclasses are predictable traps that catch intermediate developers unaware.
Also Known As
TL;DR
Explanation
PHP lacks runtime generics. PHPDoc workarounds: @template T on a class, @param T $item, @return T — PHPStan and Psalm enforce these at analysis time with zero runtime cost. @extends Repository<User> in subclasses propagates the type parameter. Patterns: typed collection classes (UserCollection extends Collection<User>), generic repositories (UserRepository extends Repository<User>). Libraries: doctrine/collections and Laravel Collection use PHPDoc generics.
Common Misconception
Why It Matters
Common Mistakes
- Not installing PHPStan or Psalm — @template annotations are just comments without static analysis
- @template without @extends or @implements in subclasses — type parameter not propagated
- Overly complex nested generic types that PHPStan cannot analyse — simplify or use interface constraints
- Runtime isinstance checks duplicating what static analysis already provides
Code Examples
// Untyped — find() returns mixed:
class UserRepository {
public function find(int $id): mixed {
return $this->db->find($id); // Returns: mixed
}
}
$user = $repo->find(42);
$user->getName(); // PHPStan: cannot call method on mixed
// PHPDoc @template — full static type safety:
/** @template T of object */
abstract class Repository {
/** @return T|null */
abstract public function find(int $id): ?object;
}
/** @extends Repository<User> */
class UserRepository extends Repository {
public function find(int $id): ?User {
return $this->db->findUser($id);
}
}
$repo = new UserRepository();
$user = $repo->find(42); // PHPStan infers: User|null
$user?->getName(); // No PHPStan error — type is known