Ce guide applique à un cas concret les notions avancées de programmation orientée objet avec PHP :
composition, injection par le constructeur, espaces de noms et chargement automatique.
La page produits.php écrite dans le guide précédent fonctionne parfaitement et permet bien de
lister les produits, en ajouter, en retirer, rediriger, afficher des messages.
Cependant, tout cela se trouve dans un seul fichier, que tu as peut-être trouvé lourd à écrire et comprendre en un clin d’oeil.
Examinons-le de plus près.
produits.php, ligne par ligne
Choisissez une responsabilité pour isoler ses lignes.
8 responsabilités, 54 lignes
Chaque couleur correspond à une raison différente de modifier ce fichier.
La validation a déjà quitté le fichier pour une fonction : c'est un premier découpage. Il reste pourtant 7 autres raisons de rouvrir cette page, et chacune oblige à relire les autres pour ne rien casser.
Huit couleurs ont été nécessaires ici, donc huit raisons différentes d’ouvrir ce fichier pour le modifier.
Changer le texte d’un message oblige à relire le SQL qui l’entoure.
Modifier la structure des données utilisées par la page oblige à retrouver les requêtes SQL dispersées dans le fichier.
Rien de tout cela n’est très grave sur un fichier de soixante lignes.
La difficulté apparaît quand les pages se multiplient et que les mêmes requêtes y sont recopiées.
VérificationUne application mobile a besoin de la liste des produits au format JSON. Quelles lignes de produits.php pouvez-vous réutiliser telles quelles ?
Aucune, en pratique. La lecture de la liste est prise entre le traitement du formulaire et le HTML ;
pour l’obtenir ailleurs, il faudrait recopier la requête SQL et la conversion des lignes. Dès que la table change,
les deux copies doivent changer ensemble, et rien ne garantit qu’on pense aux deux. C’est le symptôme typique d’une responsabilité qui n’a pas de place à elle.
Une classe devrait n’avoir qu’une seule raison de changer.
Ce principe, formulé par Robert C. Martin, ne dit pas qu’une classe ne doit faire qu’une seule chose ni contenir qu’une seule méthode. Un dépôt de produits peut lister, ajouter et supprimer : ces trois opérations changent pour la même raison, une modification de la table. Le principe demande plutôt que deux préoccupations sans rapport, comme le SQL et la mise en page, n’obligent pas à ouvrir le même fichier.
Appliqué à produits.php, le principe répartit les responsabilités ainsi.
Le point d’interrogation de ?int indique que l’identifiant peut valoir null : c’est le cas d’un produit qui vient d’être saisi et que la base n’a pas encore numéroté.
La classe est courte, mais elle est désormais le seul endroit qui connaît la clé 'message' et la règle « lire puis effacer ». Remplacer la session par un autre mécanisme ne toucherait qu’elle.
$flash->deposer($depot->supprimer($id) ?'Produit supprimé.':"Ce produit n'existait plus.");
}
header('Location: produits.php', true,303);
exit;
}
}
$produits=$depot->tous();
$message=$flash->relever();
// La partie HTML suit, avec $produit->getNom(), $produit->getPrix(), etc.
Il n’y a plus une ligne de SQL ni une seule mention de $_SESSION dans la page.
Les règles de validation vivent dans une classe que produit-modifier.php peut réutiliser telle quelle.
Un futur point d’accès API destiné à l’application mobile peut maintenant obtenir
les mêmes produits avec $depot->tous(), puis les convertir en JSON, sans recopier le SQL.
La page garde pourtant trois rôles qui ne lui reviennent pas vraiment :
elle assemble elle-même les objets dont elle a besoin, en choisissant les paramètres de chacun ;
elle connaît l’enchaînement de chaque opération : valider, construire, enregistrer, confirmer, dans cet ordre, sans rien oublier ;
elle mêle encore ce traitement au HTML qui suit.
La page sur les services et le modèle MVC confie l’enchaînement des opérations à des services, puis sépare traitement et présentation.
Une page qui mêle connexion, lecture de la requête, validation, SQL, redirection et HTML a autant de raisons de changer que de responsabilités, et chacune oblige à relire les autres.
Le principe de responsabilité unique demande qu’une classe n’ait qu’une seule raison de changer, ce qui n’implique pas qu’elle ne fasse qu’une seule chose.
Une entité représente une chose du domaine ; un dépôt est le seul à la lire et à l’écrire dans la base.
Le validateur regroupe les règles métier, réutilisables par l’ajout comme par la correction ; il vérifie, puis construit l’entité.
Isoler l’accès à la session dans une classe dédiée fait de celle-ci le seul endroit à modifier si le mécanisme change.
Après extraction, la page assemble encore les objets, enchaîne les opérations et produit le HTML : trois rôles qui relèvent des services et du modèle MVC.