Generics en PHP : guide complet de typage avec exemples

Formateur Python en ligne pour débutants

Apprenez Python facilement sans surcharge théorique. Résolvez des tâches pratiques avec vérification automatique et écrivez du code directement dans le navigateur.

Start Course

Pourquoi les Generics ne sont pas qu'une simple tendance, mais une nécessité ?

\n\n

Si vous avez déjà écrit du code PHP qui fonctionnait avec des collections, des repositories ou une couche service, vous avez sûrement été confronté à cette situation : une fonction accepte array, mais ce qu'il y a à l'intérieur reste un mystère. Peut-être des utilisateurs, peut-être des chats. Ou, pire encore, les deux. C'est là que les Generics (génériques) viennent à la rescousse — un outil de typage puissant qui rend votre code prévisible, sûr et auto-documenté.

\n\n

Dans cet article, nous allons voir comment fonctionnent les generics en PHP, pourquoi ils sont nécessaires et comment les utiliser dans des projets réels. Vous apprendrez à éviter les erreurs typiques et à rendre votre code professionnel. C'est parti !

\n\n

Qu'est-ce que les Generics en termes simples ?

\n\n

Imaginez que vous êtes développeur d'une boutique en ligne. Vous avez une classe Cart qui stocke des produits. Sans generics, vous écrivez :

\n\n
class Cart {\n    private array $items;\n    \n    public function addItem($item): void {\n        $this->items[] = $item;\n    }\n    \n    public function getItems(): array {\n        return $this->items;\n    }\n}
\n\n

Le problème ? $item peut être n'importe quoi — un nombre, une chaîne, un objet Product ou même null. L'IDE ne vous indiquera pas quel type est retourné par getItems(). Vous devrez fouiller la documentation ou déboguer.

\n\n

Les Generics résolvent ce problème. Ils permettent de préciser : « Hé, cette classe ne fonctionne qu'avec des produits ! ». Cela ressemble à ceci :

\n\n
class Cart {\n    /** @param Product[] $items */\n    private array $items;\n    \n    public function addItem(Product $item): void {\n        $this->items[] = $item;\n    }\n    \n    /** @return Product[] */\n    public function getItems(): array {\n        return $this->items;\n    }\n}
\n\n

Mais ce n'est qu'une imitation. Les véritables generics en PHP sont apparus avec PHP 8.0, et le support complet avec PHP 8.1+ grâce aux attributs et à l'analyse statique (par exemple, PHPStan ou Psalm).

\n\n

Comment fonctionnent réellement les Generics en PHP ?

\n\n

Contrairement à Java ou C#, PHP n'a pas (encore) de support natif des generics au niveau syntaxique. Cependant, grâce aux annotations PHPDoc et aux outils d'analyse statique, nous pouvons bénéficier de tous les avantages du typage.

\n\n

Types template (Template Types)

\n\n

L'approche la plus populaire consiste à utiliser @template dans PHPDoc. Prenons l'exemple d'une collection :

\n\n
/**\n * @template T\n */\nclass Collection {\n    /** @var array<int, T> */\n    private array $items = [];\n    \n    /**\n     * @param T $item\n     */\n    public function add(mixed $item): void {\n        $this->items[] = $item;\n    }\n    \n    /**\n     * @return T\n     */\n    public function get(int $index): mixed {\n        return $this->items[$index] ?? throw new \\OutOfBoundsException();\n    }\n}
\n\n

Maintenant, en utilisant cette classe, vous spécifiez le type concret :

\n\n
/** @var Collection<User> $userCollection */\n$userCollection = new Collection();\n$userCollection->add(new User('Alice'));\n$user = $userCollection->get(0); // PHPStan sait : $user est un User\necho $user->name; // Sécurisé !
\n\n

Contraintes (Constraints) pour les Generics

\n\n

Parfois, vous avez besoin que le type T ne soit pas n'importe lequel, mais qu'il implémente une interface spécifique. Cela s'appelle une bound (contrainte) :

\n\n
/**\n * @template T of \\JsonSerializable\n */\nclass JsonCollection {\n    /** @var array<int, T> */\n    private array $items = [];\n    \n    public function toJson(): string {\n        return json_encode($this->items);\n    }\n}
\n\n

Désormais, vous ne pouvez pas ajouter à la collection un objet qui n'implémente pas JsonSerializable. L'IDE et l'analyseur statique généreront une erreur.

\n\n

Exemples pratiques : du simple au complexe<

Blogs

Book Recommendations