Introduction : PHP et la POO, une histoire de maturation
Il fut un temps où PHP était synonyme de code spaghetti, de variables globales et de scripts procéduraux entremêlés de HTML. Cette époque est révolue. Le PHP moderne, à partir de la version 7.0 et surtout avec PHP 8, offre un support de la programmation orientée objet qui n'a rien à envier à des langages comme Java, C# ou TypeScript.
Cette évolution n'est pas un hasard. Elle résulte d'un effort conscient de la communauté PHP pour adopter les bonnes pratiques du génie logiciel. Les frameworks comme Symfony et Laravel ont joué un rôle majeur dans cette transformation en imposant des standards élevés de qualité de code. Aujourd'hui, un développeur PHP qui écrit du code propre et bien structuré est aussi compétent que n'importe quel développeur dans un autre langage.
Si vous découvrez PHP, consultez d'abord notre article 10 raisons pour lesquelles j'aime PHP pour comprendre l'attrait global du langage.
Le typage strict : la fondation du code fiable
L'une des avancées les plus significatives du PHP moderne est le typage strict. Avec la déclaration declare(strict_types=1), PHP passe d'un langage à typage faible à un langage à typage strict par fichier. Les paramètres de fonctions, les types de retour et les propriétés de classes peuvent tous être typés.
PHP 8 a enrichi considérablement le système de types avec les types union (int|string), les types d'intersection (Countable&Iterator), le type never, le type null standalone, et les types true et false comme types autonomes. Ces ajouts permettent d'exprimer des contraintes précises sur les données que manipule votre code.
Le typage strict n'est pas qu'une question de rigueur académique. Il apporte des avantages concrets : meilleure autocomplétion dans l'IDE, détection précoce des bugs, documentation intégrée au code, et facilitation du refactoring. Quand vous changez la signature d'une méthode, PHP vous signale immédiatement tous les endroits où le contrat est violé.
Interfaces et contrats : programmer par abstraction
Les interfaces en PHP sont l'outil fondamental pour la programmation par contrat. Une interface définit un ensemble de méthodes qu'une classe doit implémenter, sans spécifier comment. Cela permet de découpler le code et de le rendre plus flexible.
Prenons un exemple concret. Vous avez un service qui envoie des notifications. Plutôt que de coupler votre code à un service d'email spécifique, vous définissez une interface NotificationChannelInterface avec une méthode send(Notification $notification): void. Vous pouvez ensuite créer des implémentations pour l'email, le SMS, Slack, les push notifications... et les interchanger sans modifier le code appelant.
Ce pattern est au cœur du principe d'inversion de dépendance (le "D" de SOLID). Il est utilisé massivement dans les frameworks PHP modernes. Symfony, par exemple, repose entièrement sur des interfaces pour ses composants, ce qui les rend interchangeables et testables.
Depuis PHP 8.0, les interfaces supportent les méthodes avec des types de retour static, et PHP 8.1 a introduit les constantes dans les enums qui peuvent implémenter des interfaces. Ces évolutions rendent les interfaces encore plus puissantes.
Classes abstraites et héritage
Les classes abstraites occupent une place intermédiaire entre les interfaces et les classes concrètes. Elles peuvent définir des méthodes abstraites (sans implémentation) et des méthodes concrètes (avec implémentation). C'est l'outil idéal pour le pattern Template Method : la classe abstraite définit l'algorithme général, et les sous-classes implémentent les étapes spécifiques.
L'héritage en PHP suit le modèle de l'héritage simple : une classe ne peut hériter que d'une seule classe parente. Cette restriction, loin d'être une limitation, encourage une conception plus propre. Au lieu de créer des hiérarchies de classes profondes et complexes, les développeurs PHP modernes préfèrent la composition à l'héritage.
Avec la promotion des propriétés dans le constructeur (PHP 8.0), les classes abstraites deviennent encore plus concises. Un constructeur comme public function __construct(protected readonly string $name) déclare, initialise et protège une propriété en une seule ligne.
Les traits : la réutilisation horizontale
Les traits sont la réponse de PHP au problème de la réutilisation de code entre classes non liées par l'héritage. Un trait est un ensemble de méthodes qui peut être "inclus" dans n'importe quelle classe via le mot-clé use.
Les cas d'utilisation classiques des traits incluent : l'ajout de fonctionnalités de logging, la gestion des timestamps (created_at, updated_at), le soft delete, la gestion du cache, ou encore la sérialisation. Laravel utilise massivement les traits dans ses modèles Eloquent : SoftDeletes, HasFactory, Notifiable.
Il est important de ne pas abuser des traits. Un trait qui grossit démesurément ou qui accède à des propriétés de la classe hôte (via $this) de manière opaque est un signe de mauvaise conception. Les traits fonctionnent mieux quand ils encapsulent un comportement autonome et bien défini.
Namespaces et autoloading
Les namespaces, introduits en PHP 5.3, ont révolutionné l'organisation du code PHP. Fini les noms de classes à rallonge comme Zend_Db_Table_Row_Abstract. Avec les namespaces, vous organisez vos classes dans une hiérarchie logique : App\Models\User, App\Services\PaymentService, App\Http\Controllers\UserController.
Combiné avec Composer et l'autoloading PSR-4, les namespaces permettent un chargement automatique des classes. Plus besoin de require ou include manuels. Quand vous écrivez use App\Models\User;, Composer sait automatiquement où trouver le fichier correspondant. C'est simple, propre et performant.
Les standards PSR (PHP Standard Recommendations) ont joué un rôle crucial dans la maturation de PHP. PSR-4 (autoloading), PSR-7 (HTTP messages), PSR-11 (container), PSR-12 (coding style) : ces standards assurent l'interopérabilité entre les différentes bibliothèques et frameworks PHP.
Les apports de PHP 8 pour la POO
PHP 8.0 a été une révolution pour la POO en PHP. La promotion des propriétés dans le constructeur réduit considérablement le code boilerplate. Les @@X
201@@named arguments rendent les appels de constructeurs complexes lisibles. Les attributs (annotations natives) remplacent les docblocks pour les métadonnées structurées.
PHP 8.1 a introduit les enums, une fonctionnalité attendue depuis des années. Les enums PHP sont des objets à part entière : ils peuvent implémenter des interfaces, avoir des méthodes, et les backed enums associent une valeur scalaire à chaque cas. Les fibers ouvrent la porte à la programmation asynchrone native.
PHP 8.2 a apporté les classes en lecture seule (readonly class), qui rendent toutes les propriétés immutables par défaut. C'est idéal pour les Value Objects et les DTO. Les types true, false et null comme types autonomes affinent encore le système de types.
PHP 8.3 et 8.4 continuent cette trajectoire avec les constantes typées dans les classes, le clonage en lecture seule, les property hooks et l'asymmetric visibility. Chaque version renforce les capacités POO de PHP.
| Version PHP | Apport POO majeur |
|---|---|
| PHP 8.0 | Promotion des propriétés, named arguments, attributs |
| PHP 8.1 | Enums, fibers, types d'intersection |
| PHP 8.2 | Readonly classes, types true/false/null autonomes |
| PHP 8.3/8.4 | Constantes typées, property hooks, asymmetric visibility |
Appliquer les principes SOLID en PHP
Le PHP moderne fournit tous les outils nécessaires pour appliquer les principes SOLID dans vos projets. Le principe de responsabilité unique (SRP) est facilité par les namespaces et la structure PSR-4. Le principe ouvert/fermé (OCP) s'appuie sur les interfaces et l'injection de dépendances. Le principe de substitution de Liskov (LSP) est renforcé par le typage strict et les types covariants/contravariants.
Le principe de ségrégation des interfaces (ISP) encourage à créer des interfaces fines et spécifiques plutôt que des interfaces monolithiques. Et le principe d'inversion de dépendance (DIP) est naturellement supporté par les containers d'injection de dépendances de Symfony et Laravel.
Pour approfondir ces concepts dans un contexte plus large, découvrez notre article sur la programmation orientée objet.