Un site écrit sans framework commence toujours proprement : une en-tête incluse en haut de chaque page, un pied de page en bas, et le contenu au milieu. Puis une page a besoin d'une balise supplémentaire dans l'en-tête, une autre d'un corps différent, une troisième d'un script particulier. On ajoute des conditions dans le fichier commun, puis on duplique, et deux ans plus tard le site comporte quatre en-têtes légèrement différentes que personne n'ose plus toucher. L'organisation des gabarits d'un site fait main se règle avec deux mécanismes simples, l'héritage et les fragments, qui suppriment à peu près tous les cas de duplication sans imposer d'outil supplémentaire.
Ce qu'une vue doit et ne doit pas faire
La règle qui gouverne toute l'organisation est celle de la séparation entre la préparation des données et leur affichage. Elle est simple à énoncer et constamment violée dans les projets écrits à la main. Cette question s'inscrit dans la structuration générale d'un projet, sujet que nous traitons dans notre article sur la manière de structurer un projet PHP sans framework.
Une vue affiche, elle ne calcule pas
Un fichier de vue doit contenir du balisage, des boucles d'affichage, des conditions simples et rien d'autre. Aucune requête de base, aucun appel réseau, aucun calcul métier. Cette discipline paraît excessive au moment de coder et se paie immédiatement dès qu'il faut modifier quelque chose : une vue contenant des requêtes ne peut être ni réutilisée, ni testée, ni comprise sans exécuter le site. Elle rend également impossible toute mise en cache sélective, puisqu'on ne sait plus ce que l'affichage déclenche réellement. La règle se vérifie en cherchant les mots clés de la couche d'accès aux données dans le répertoire des vues : le résultat doit être vide.
Les données arrivent explicitement
Une vue doit recevoir ses données par un moyen explicite, un tableau de variables préparé par le code appelant, plutôt que de piocher dans des variables globales. La différence est considérable en pratique : on peut lire une vue et savoir exactement de quoi elle a besoin, ce qui est la condition pour la réutiliser ailleurs. Une vue qui dépend de l'état global du programme ne peut être déplacée sans casser, et c'est précisément ce qui bloque les réorganisations tentées trop tard. Le passage explicite coûte une ligne au moment de l'appel et fait gagner des heures dès la première réutilisation.
Les conditions restent simples
Une condition dans une vue doit se limiter à décider si un bloc s'affiche ou non. Dès qu'une condition en contient une autre et qu'il faut relire trois fois pour comprendre ce qui sera produit, la logique appartient au code appelant. La solution consiste à préparer une variable booléenne au nom explicite dans le contrôleur et à ne tester que celle ci dans la vue, ce qui rend le gabarit lisible par quelqu'un qui ne connaît pas le métier. Le nom de cette variable doit exprimer l'intention plutôt que la condition technique, ce qui rend la vue compréhensible sans contexte.
L'échappement se fait dans la vue
C'est la seule opération de traitement qui a sa place dans un gabarit, et elle doit y être systématique. Le contexte de sortie n'est connu qu'au moment de l'affichage, ce qui rend impossible un échappement fait en amont. Ce point est développé dans notre article sur la manière d'échapper correctement ses sorties en PHP, et il constitue l'argument le plus solide en faveur d'une séparation nette entre préparation et affichage. Une fonction d'échappement courte, au nom bref, rend cette systématicité supportable dans un gabarit chargé.
Une vue ne redirige pas
Envoyer un en-tête de redirection depuis un gabarit ne fonctionne que si aucune sortie n'a encore été produite, condition rarement remplie à ce stade. Plus fondamentalement, une redirection est une décision, et les décisions se prennent avant l'affichage. Ce défaut se rencontre sur les sites où le contrôle d'accès a été ajouté après coup, directement en tête des gabarits, avec les erreurs d'en-têtes déjà envoyés qui en découlent. Le contrôle d'accès doit se faire dans le point d'entrée ou dans le contrôleur, avant toute production de sortie, sans exception.

L'héritage de gabarit
L'héritage résout le problème des pages qui partagent une structure commune tout en devant en modifier certaines parties. Le mécanisme est décrit en détail dans notre article sur la façon d'écrire un système de gabarits en PHP pur.
Le principe de l'inversion
Dans l'approche classique par inclusion, la page inclut l'en-tête puis le pied. Dans l'approche par héritage, la page déclare quel gabarit parent elle utilise et remplit des blocs nommés, le parent décidant de la structure. L'inversion est décisive : c'est le gabarit commun qui contrôle l'ordre et l'imbrication, et non chaque page qui doit s'en souvenir. Toute modification de structure se fait alors en un seul endroit. Ce seul changement de perspective supprime la plupart des duplications que l'on constate sur les sites anciens.
Les blocs nommés
Un bloc est une zone du gabarit parent que l'enfant peut remplir : le titre, le contenu principal, les balises supplémentaires de l'en-tête, les scripts de fin de page, une colonne latérale. Un jeu de cinq à sept blocs couvre l'essentiel des besoins d'un site ordinaire. Il faut résister à la tentation d'en multiplier le nombre : au delà d'une dizaine, plus personne ne se souvient de leur rôle et l'héritage devient aussi confus que ce qu'il remplaçait.
Les valeurs par défaut
Chaque bloc doit avoir un contenu par défaut dans le parent, affiché lorsque l'enfant ne le remplit pas. Cela permet à une page simple de ne définir que son contenu principal, sans avoir à déclarer tous les blocs. Cette valeur par défaut sert aussi de documentation : lire le gabarit parent suffit à savoir ce qui existe et ce que chaque bloc contient habituellement, ce qui évite d'avoir à chercher dans les pages enfants. Un bloc de titre par défaut reprenant le nom du site est un exemple typique de valeur par défaut utile.
L'implémentation par capture
La mise en œuvre la plus simple consiste à capturer la sortie de la vue enfant dans un tampon, à enregistrer les blocs qu'elle définit dans un tableau, puis à inclure le gabarit parent qui les affiche là où il le souhaite. Une trentaine de lignes suffisent à écrire ce mécanisme. Il n'y a aucune raison d'installer une bibliothèque de plusieurs milliers de lignes pour obtenir ce résultat sur un site de taille modeste. Le code obtenu reste lisible, modifiable et parfaitement compris de celui qui reprendra le projet.
L'héritage sur plusieurs niveaux
Un gabarit de base définissant la structure du document, un gabarit intermédiaire ajoutant une colonne latérale, et des pages héritant de l'un ou de l'autre couvrent la quasi totalité des besoins. Trois niveaux constituent une limite raisonnable ; au delà, la chaîne devient difficile à suivre et l'on perd le bénéfice de la clarté. Cette contrainte est saine et pousse à réfléchir avant d'ajouter un niveau supplémentaire. Un quatrième niveau signale généralement qu'un fragment aurait mieux convenu qu'un gabarit intermédiaire.
Ce que l'héritage ne résout pas
L'héritage organise la structure verticale d'une page, il ne traite pas la réutilisation d'éléments apparaissant à plusieurs endroits, comme une carte de produit ou un formulaire de recherche. Ces éléments relèvent des fragments, mécanisme complémentaire et différent. Confondre les deux conduit à des gabarits parents surchargés de conditions destinées à afficher tel ou tel élément selon la page, ce qui est exactement le problème que l'héritage devait supprimer. La distinction entre les deux mécanismes doit donc être posée dès le départ et rappelée en relecture.
| Besoin | Mécanisme | Erreur fréquente |
|---|---|---|
| Structure commune de page | Héritage de gabarit | Inclusions en tête et en pied |
| Élément répété dans une page | Fragment paramétré | Copie du balisage |
| Variante de mise en page | Gabarit intermédiaire | Conditions dans le parent |
| Contenu propre à une page | Bloc nommé | Variable globale |
| Script propre à une page | Bloc de fin de document | Balise écrite dans le contenu |
| Données à afficher | Tableau passé explicitement | Accès direct à l'état global |
Les fragments réutilisables
Un fragment est un morceau de balisage appelé avec des paramètres, l'équivalent d'une fonction pour l'affichage. C'est le mécanisme qui supprime le plus de duplication sur un site réel.
Un fragment prend des paramètres
Un fragment de carte produit reçoit le produit à afficher et éventuellement une option de taille ou de contexte. Il ne va rien chercher lui même. Cette discipline permet de l'utiliser dans une liste de catégorie, dans un bloc de produits associés, dans les résultats de recherche et dans un courriel, sans modification. C'est exactement le bénéfice recherché, et il disparaît dès qu'un fragment consulte l'état global pour compléter ce qu'on ne lui a pas passé. Le test de réutilisabilité est simple : si le fragment fonctionne dans un contexte où l'état global n'existe pas, il est correctement écrit.
Des paramètres nommés et documentés
Un commentaire en tête du fragment listant les paramètres attendus, leur type et leur caractère obligatoire évite de devoir lire tout le code pour l'utiliser. Cette documentation de trois lignes est ce qui distingue un fragment réellement réutilisé d'un fragment que chacun recopie parce qu'il ne sait pas comment l'appeler. Elle prend moins de temps à écrire qu'une seule recherche dans le code six mois plus tard. Elle sert aussi de contrat, en rendant explicite ce que le fragment attend et ce qu'il ne fera pas.
Des valeurs par défaut
Un fragment doit fonctionner avec le minimum de paramètres et compléter le reste par des valeurs par défaut raisonnables. Un appel sans option produit alors le cas le plus courant, ce qui rend l'usage quotidien confortable. Cette souplesse suppose de fusionner les paramètres reçus avec un tableau de valeurs par défaut, exactement comme on le fait pour les attributs d'un composant, et de ne jamais accéder directement à une clé sans garantie de son existence. Une clé absente produit un avertissement qui pollue les journaux et finit par masquer les erreurs réelles.
La granularité
Un fragment trop gros n'est jamais réutilisable, un fragment trop petit multiplie les fichiers sans bénéfice. La bonne granularité correspond à un élément que l'on désigne par un nom dans une conversation d'équipe : une carte produit, un fil d'ariane, un bloc d'avis, une pagination. Si l'élément n'a pas de nom naturel, c'est probablement qu'il ne mérite pas d'être extrait, critère empirique remarquablement fiable. Il évite les débats de principe sur la bonne taille d'un composant, question sur laquelle personne ne s'accorde jamais.
Les fragments qui affichent des listes
Un fragment de liste doit recevoir la collection à afficher plutôt que d'aller la chercher, et il doit gérer le cas de la collection vide en affichant un message plutôt que rien. Ce dernier point est systématiquement oublié et produit des blocs qui disparaissent sans explication, laissant le visiteur devant une zone vide. Prévoir ce cas dès l'écriture coûte deux lignes et évite un ticket un an plus tard. Le message affiché doit être utile, en proposant une action plutôt qu'en constatant simplement l'absence de résultat.
Ne pas confondre fragment et composant client
Un fragment produit du balisage côté serveur. Un composant écrit en JavaScript produit du balisage côté navigateur. Les deux peuvent coexister mais ne se remplacent pas, et un site fait main gagne à privilégier le premier, moins coûteux à la première visite et fonctionnant sans script. Réserver le second aux éléments réellement interactifs, plutôt que de tout basculer côté client par principe, garde le site rapide et robuste. Un site dont l'essentiel du balisage est produit côté serveur reste par ailleurs entièrement lisible par les moteurs, sans dépendre de leur capacité d'exécution.
Origines relevées lors de reprises de sites écrits sans framework. Les deux premières se règlent par l'héritage et les fragments.
Organisation des fichiers et entretien
Le rangement des fichiers compte autant que les mécanismes, parce qu'il détermine si l'on retrouve ce que l'on cherche en dix secondes ou en dix minutes.
Un répertoire par nature
Trois répertoires suffisent : un pour les gabarits parents, un pour les vues correspondant à des pages, un pour les fragments. Cette séparation rend immédiatement lisible le rôle de chaque fichier et évite le répertoire fourre tout où quarante fichiers se côtoient sans hiérarchie. Elle facilite également les recherches, un nom de fragment ne pouvant pas être confondu avec un nom de page. Sur un projet volumineux, un sous répertoire par section à l'intérieur de celui des vues garde l'ensemble navigable.
Un nommage prévisible
Le nom du fichier doit correspondre à ce qu'il affiche, dans une convention unique appliquée partout. Sur un site comportant plusieurs sections, un préfixe correspondant à la section évite les collisions et regroupe visuellement les fichiers liés. Cette convention doit être écrite quelque part, faute de quoi elle dérive dès que deux personnes travaillent sur le projet, et la dérive est irréversible en pratique. Deux lignes dans le fichier de description du projet suffisent à fixer cette convention pour de bon.
Aucun accès direct
Les fichiers de vue ne doivent pas être accessibles par une adresse. Le plus simple consiste à les placer en dehors du répertoire servi publiquement, solution radicale et définitive. Lorsque ce n'est pas possible, un contrôle en tête de chaque fichier vérifiant qu'il a bien été inclus par le point d'entrée du site remplit le même office, avec une ligne par fichier. Cette ligne se copie mécaniquement et doit figurer dans le modèle de fichier utilisé pour créer une nouvelle vue.
Le cas des vues d'erreur
Les pages d'erreur méritent leurs propres vues, héritant du gabarit de base pour conserver l'apparence du site. Une page d'erreur affichant un message brut du serveur donne une impression déplorable et révèle parfois des informations techniques. Ces vues doivent en outre fonctionner même quand une partie du site est indisponible, ce qui suppose qu'elles ne dépendent d'aucune donnée dynamique, contrainte à respecter dès leur écriture. Une page d'erreur reposant sur une requête de base devient inaccessible précisément le jour où la base est indisponible.
Éviter la logique qui revient
Malgré la meilleure discipline, du code métier finit par apparaître dans les vues, généralement lors d'une correction faite dans l'urgence. Une relecture périodique des gabarits, à la recherche de requêtes ou de calculs, permet de les remettre à leur place avant que la situation ne se dégrade. Cette relecture prend une heure sur un site de taille moyenne et mérite d'être programmée plutôt qu'espérée.
Documenter la structure
Un fichier de quelques lignes décrivant les gabarits disponibles, les blocs qu'ils exposent et les fragments existants transforme un projet impénétrable en projet abordable. C'est le document que l'on regrette de ne pas avoir écrit chaque fois qu'on reprend un site après une longue interruption. Il se maintient en quelques minutes à chaque ajout, à condition d'en prendre l'habitude dès le début du projet. Il tient en un schéma et une dizaine de lignes de commentaire, format qui résiste au temps bien mieux qu'une documentation détaillée que personne ne met à jour.
💬 0 commentaires
✍️ Laisser un commentaire
Créez un compte gratuit ou connectez-vous pour commenter.