← CodeClarityLab Home
Browse by Category
+ added · updated 7d
← Back to glossary

Generics Workarounds in PHP

php PHP 7.0+ Advanced
debt(d5/e3/b5/t5)
d5 Detectability Operational debt — how invisible misuse is to your safety net

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.

e3 Effort Remediation debt — work required to fix once spotted

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.

b5 Burden Structural debt — long-term weight of choosing wrong

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.

t5 Trap Cognitive debt — how counter-intuitive correct behaviour is

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.

About DEBT scoring →

Also Known As

PHP generics @template PHPDoc generics typed collections PHPStan generics

TL;DR

PHPDoc @template annotations with PHPStan/Psalm provide compile-time type-safe generics with zero runtime cost — the standard approach for typed collections and repositories.

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

PHP cannot have type-safe collections without runtime cost — PHPDoc @template annotations with PHPStan/Psalm provide full compile-time type safety with zero runtime overhead.

Why It Matters

A Repository<User> that statically enforces find() returns User|null catches type errors at analysis time before deployment, rather than as TypeErrors in production.

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

✗ Vulnerable
// 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
✓ Fixed
// 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

Added 16 Mar 2026
Edited 22 Mar 2026
Views 23
Rate this term
No ratings yet
🤖 AI Guestbook educational data only
| |
Last 30 days
0 pings T 0 pings F 0 pings S 0 pings S 1 ping M 0 pings T 1 ping W 0 pings T 0 pings F 0 pings S 0 pings S 0 pings M 0 pings T 1 ping W 1 ping T 0 pings F 0 pings S 0 pings S 1 ping M 0 pings T 1 ping W 0 pings T 0 pings F 1 ping S 0 pings S 0 pings M 0 pings T 0 pings W 0 pings T 0 pings F
No pings yet today
No pings yesterday
Amazonbot 8 Perplexity 4 Unknown AI 2 Google 2 Ahrefs 2 Claude 1
crawler 18 crawler_json 1
DEV INTEL Tools & Severity
🟢 Low ⚙ Fix effort: Medium
⚡ Quick Fix
Use PHPStan/Psalm @template generics in docblocks — they're not native PHP but static analysers enforce them, giving you generic type safety without runtime overhead
📦 Applies To
PHP 7.0+ web cli queue-worker
🔗 Prerequisites
🔍 Detection Hints
Collection class returning array with no element type; missing @template on generic collection; type-unsafe getItems() returning mixed
Auto-detectable: ✓ Yes phpstan psalm
⚠ Related Problems
🤖 AI Agent
Confidence: Low False Positives: Medium ✗ Manual fix Fix: Medium Context: File

✓ schema.org compliant