Generics en PHP : pourquoi en avez-vous besoin et comment les utiliser
Les types génériques (Generics) sont l'une des fonctionnalités les plus attendues et discutées dans le monde PHP. Bien qu'ils ne soient pas encore officiellement implémentés dans le langage à partir de PHP 8.x, la communauté utilise activement des approches alternatives et attend un support complet. Dans cet article, nous allons voir pourquoi les Generics sont nécessaires en PHP, comment les émuler et quels avantages ils apportent au développeur.
Que sont les Generics et pourquoi en avez-vous besoin ?
Les Generics (génériques) permettent de créer des classes, des interfaces et des fonctions qui fonctionnent avec différents types de données, tout en conservant un typage strict. Dans les langages à typage statique (Java, C#, TypeScript), ils sont déjà devenus la norme. Pour PHP, qui était initialement typé dynamiquement, les Generics sont un pas vers un code plus fiable et plus lisible.
Les principaux problèmes résolus par les Generics :
- Sécurité des types — ils éliminent les erreurs liées à la transmission de données d'un type incorrect.
- Réduction de la duplication de code — inutile d'écrire des classes séparées pour chaque type.
- Amélioration de la lisibilité — on comprend immédiatement avec quels types la fonction ou la classe travaille.
- Support IDE — l'autocomplétion et l'analyse du code deviennent plus précises.
Le problème sans Generics : exemple en PHP
Imaginez que vous deviez créer une collection qui ne stocke que des nombres entiers. Sans Generics, vous pouvez écrire :
class IntegerCollection { private array $items = [];
public function add(int $item): void { $this->items[] = $item; }
public function get(int $index): int { return $this->items[$index]; }}Tout fonctionne, mais si vous avez besoin d'une collection pour les chaînes de caractères, vous devrez copier le code et changer les types. Et si vous avez besoin d'une collection pour les objets — la même chose. Cela conduit à une duplication et à une augmentation du volume de code.
Émulation des Generics en PHP avec des annotations et PHPDoc
Actuellement, PHP ne prend pas en charge les Generics complets au niveau de la syntaxe, mais ils peuvent être émulés à l'aide d'annotations PHPDoc et de bibliothèques spéciales (par exemple, phpstan/phpstan ou vimeo/psalm).
Exemple d'une classe générique avec annotations :
/** * @template T */class Collection { private array $items = [];
/** * @param T $item */ public function add($item): void { $this->items[] = $item; }
/** * @return T */ public function get(int $index) { return $this->items[$index]; }}Maintenant, lors de l'utilisation de la classe, vous pouvez spécifier un type concret :
/** @var Collection<int> $intCollection */$intCollection = new Collection();$intCollection->add(42);$value = $intCollection->get(0); // IDE sait que c'est un intLes analyseurs statiques (PHPStan, Psalm) vérifieront que vous ne passez pas une chaîne de caractères dans une collection d'entiers. Cela offre presque la même sécurité que les Generics complets.
Exemples réels d'utilisation des Generics en PHP
Examinons plusieurs scénarios pratiques où les Generics sont particulièrement utiles.
1. Repositories dans Doctrine
Dans Doctrine ORM, vous travaillez souvent avec des repositories. Les Generics aident à spécifier explicitement avec quelle entité le repository travaille :
/** * @template T of object */interface RepositoryInterface { /** * @param int $id * @return T|null */ public function find(int $id): ?object;}
/** * @implements RepositoryInterface<User> */class UserRepository implements RepositoryInterface { public function find(int $id): ?User { // logique de recherche }}2. Patron "Stratégie" avec génériques
Les Generics permettent de créer