PSR mon amour : 50 nuances de conventions
Découvrez les PSR en PHP, ces standards qui promettent de transformer notre code et de nous permettre de faire revenir l'être aimé, faire le café et ranger la forêt. Style, autoload, logs, HTTP : tout y passe !
Bienvenue dans le monde merveilleux des PSR sont ces fameuses PHP Standard Recommendations qui nous promettent amour, gloire et beauté. Officiellement, il s’agit d’un ensemble de standards visant à améliorer les pratiques de programmation en PHP et l’interopérabilité entre les frameworks . En gros, le PHP-FIG (Framework Interop Group), sorte d’ONU des développeurs PHP, s’est dit un jour : « Et si on essayait de faire ranger sa chambre à la communauté PHP ? » – comprendre, fixer des règles pour que tout le monde code un peu pareil.
FIG, kézako ? Le PHP-FIG est un groupe fondé en 2009 rassemblant des lead dev de frameworks PHP. Leur but affiché : « trouver des moyens de mieux travailler ensemble » . Avouons que c’est plus sympa que de se taper à coup de pelle éternellement sur des histoires d’accolades ou de tabulations.
Au fil du temps, ce cénacle a pondu une série numérotée de recommandations baptisées PSR-1, PSR-2, etc., censées apporter la paix et l’harmonie dans le code… ou pas…
Certaines sont devenues incontournables, d’autres ont fini au cimetière des bonnes idées comme le fait si bien Google.
PSR-1 : Les bases du code PHP
La PSR-1, adoptée en 2012, est le point de départ : le B.A.-BA pour coder proprement en PHP. Elle pose les normes de codage de base requises pour une interopérabilité technique optimale . En clair, c’est une checklist des bonnes manières dès qu’on écrit un fichier PHP :
- Balises PHP standard : on n’utilise que
<?php ... ?>
et éventuellement la courte<?= ... ?>
. Exit les antiques<% %>
ou<?
tout court ! . Non, votre code n’est pas une rave party de balises exotiques. - Encodage : tout le code en UTF-8 sans BOM (oui, même toi au fond qui code encore en ISO-8859-1). C’est 2025, on aime les émojis et les caractères spéciaux, alors on s’uniformise !
- Organisation des fichiers : un fichier PHP doit soit déclarer des symboles (classes, fonctions, constantes…), soit produire des effets de bord (faire des
echo
, modifierini_set
, etc.), mais pas les deux en même temps . En d’autres termes, arrêtons les fichiers qui définissent une classe et en profitent pour lancer une petite requête DB en douce : on sépare les responsabilités ! - Autoload oblige : chaque classe doit être dans un fichier à part, avec un namespace cohérent, conformément à un standard d’autoloading (on reviendra sur PSR-4 plus bas). Fini les fichiers fourre-tout avec 36 classes dedans.
- Nommage : on fixe des conventions lisibles par tous : Classes en StudlyCaps, constantes de classe en MAJUSCULES_AVEC_DES_TIRES_BAS, méthodes en camelCase . Parce que
MaSuperClasse
ça fait plus pro queMa_super_classe_du_feu
, etgetUserName()
c’est quand même plus sobre queGetUserName
ouget_user_name
.
En résumé, PSR-1 c’est un peu le code de la route du dev PHP : des règles élémentaires pour éviter les accidents de lecture de code. Par exemple, voici un mini-code respectant PSR-1 :
<?php
namespace MonProjet\Util;
class MaSuperClasse {
const VERSION = '1.0';
public function faisUnTruc() {
// ...
}
}
Ici, on a bien nos tags <?php
d’ouverture, un namespace MonProjet\Util
cohérent avec l’arborescence, un nom de classe MaSuperClasse
en StudlyCaps, une constante VERSION
en majuscules, et une méthode faisUnTruc()
en camelCase. Ouf, l’honneur est sauf.
La PSR-1, c’est un peu comme apprendre à dire « bonjour » et « merci » en société. Basique, mais quand on voit certains vieux scripts PHP dans la nature, on se dit que ça ne fait pas de mal de le rappeler. Allez, range ta chambre, développeur, et n’oublie pas de fermer la porte avec un ?>
… ou plutôt non, on ne ferme pas la balise PHP en fin de fichier si y’a que du PHP (ça c’est aussi une bonne pratique implicite, merci). En tout cas, avec PSR-1, plus d’excuse pour les constantes nommées MaConstanteSecrete
en camelCase : ici c’est MA_CONSTANTE_SECRETE
, et en majuscules s’il vous plaît !
PSR-2 : Guide de style de codage
Si la PSR-1 est la base, PSR-2 vient fignoler la présentation. Publiée initialement en 2012, elle a fixé tout un tas de détails de mise en forme du code pour réduire ce qu’ils appellent la “friction cognitive” quand on lit du code de plusieurs auteurs . En gros, que le code soit écrit par Alice ou Bob, il devrait ressembler à du code PHP standardisé, histoire qu’on passe plus de temps à comprendre la logique qu’à buter sur du formatage bizarre.
Quelles règles le grand livre PSR-2 nous assène-t-il ? Voici le best-of des exigences :
- Indents à 4 espaces, pas de tabulations . Oui, on tranche (pardon aux talibans du tab). 4 espaces, c’est la loi, point. Si t’es pas content, va configurer ton IDE pour qu’il le fasse pour toi.
- Longueur des lignes : pas de limite stricte, mais on recommande 120 caractères max, et idéalement 80 . Au-delà, ton code devient une tartine illisible – coupe-le en morceaux, merci.
- Sauts de ligne stratégiques : une ligne vide après la déclaration de namespace, une ligne vide après le bloc de use … Histoire d’aérer tout ça comme un vieux vinyle.
- Accolades bien placées : pour les classes et fonctions, l’accolade ouvrante doit être sur la ligne suivante (et la fermante sur sa propre ligne après le corps) . Fini les styles K&R ou One True Brace en plein milieu : ici c’est Allman style, chaque accolade a sa ligne dédiée, propre, qui sent la lavande.
- Visibilité explicite : toutes les méthodes et propriétés doivent déclarer public/private/protected, et dans le bon ordre avec abstract/final d’abord, static après . En clair, plus de function obscure() sans précisions : ce sera public function, private static, etc., bien étiqueté.
- Espaces et compagnie : un espace après les mots-clés des structures de contrôle (
if
,for
…) mais pas entre le nom de fonction et sa parenthèse . Par exempleif ($x)
et nonif( $x )
. Subtilités, quand tu nous tiens. - Parenthèses : pas d’espace après une parenthèse ouvrante ni avant une fermante dans les structures de contrôle . On évite
if ( $x )
(trop d’espaces) ouwhile( $y<10 )
(pas assez après lewhile
). Bref,PSR-2
était du genre tatillon sur la ponctuation du code.
Et la liste continue sur la longueur des lignes, l’absence de whitespace en fin de ligne, une seule instruction par ligne, etc. Tout un poème. Pour illustrer, voici à quoi ressemble un code conforme PSR-2 :
class Demo
{
public function doStuff($x, $y = null)
{
if ($x === $y) {
echo "égal";
} elseif ($x > $y) {
echo "plus grand";
} else {
echo "plus petit";
}
}
}
Observez les accolades : ouvrante à la ligne suivante pour la classe et la fonction, indentations de 4 espaces, pas de tabulations, des if bien espacés… On pourrait presque sortir la loupe pour vérifier qu’il n’y a pas une espace en trop ou manquante. PSR-2, c’est un peu l’instituteur maniaque du style de code qui te tape sur les doigts quand tu mets ta virgule au mauvais endroit. Mais l’intention est louable : que notre code, à défaut d’être parfait, ait au moins bonne mine et cohérence d’un projet à l’autre .
PSR-2 a été pendant longtemps la star des linter PHP. Mais (plot twist) en 2019, on l’a déclarée obsolète et remplacée par sa grande sœur, PSR-12 . Eh oui, même les standards vieillissent : PSR-2 nous interdisait rien de spécifique sur les typed properties ou le strict_types (inconnus à l’époque), et globalement elle a bien fait son job jusqu’à ce que PHP évolue. Ne vous inquiétez pas, on enchaîne avec PSR-12 juste après.
En attendant, si vous croisez un dev qui chipote sur une accolade mal alignée, dites-lui gentiment : « Namasté ma gueule, l’esprit de la PSR-2 est en toi, jeune padawan du code bien formaté ».
PSR-3 : Logger Interface
Passons à autre chose que le style visuel : PSR-3, publiée en 2013, qui standardise la journalisation (logging) des applications PHP. En clair, elle définit une interface commune pour les bibliothèques de log . Pourquoi ? Pour permettre à n’importe quel bout de code (framework ou lib tierce) de balancer ses messages de log au travers d’un logger central sans se soucier de l’implémentation derrière . Un peu comme un standard universel du « note ça quelque part ».
Concrètement, la PSR-3 introduit l’interface Psr\Log\LoggerInterface
avec huit méthodes correspondant aux fameux niveaux de log (débbugage, info, notice, warning, error, critical, alert, emergency) . Oui, huit niveaux, rien que ça – du petit pépin (debug) à « tout est en flammes » (emergency). Pour les indécis, il y a même une neuvième méthode log($level, $message, $context) qui prend en paramètre le niveau souhaité . En gros, « appelle-moi avec le niveau que tu veux, on gère ». Si tu t’amuses à passer un niveau inconnu, ça doit lancer une InvalidArgumentException – parce qu’il y a des limites au freestyle, hein.
Voici un exemple simple d’utilisation de PSR-3 dans la nature :
use Psr\Log\LoggerInterface;
function traiterTruc(LoggerInterface $logger, $donnee) {
$logger->info("Traitement de la donnée en cours", ['data' => $donnee]);
// ... suite du traitement ...
if (!$donnee) {
$logger->warning("Donnée vide, attention !");
}
}
Ici, la fonction accepte n’importe quel LoggerInterface. Du coup, tu peux lui passer un Monolog
, un Zend\Log
, bref ce que tu veux du moment que ça respecte PSR-3. On utilise $logger->info()
pour noter une info avec un contexte (un tableau associatif ['data' => $donnee]), ou $logger->warning()
pour signaler un petit souci. Grâce à PSR-3, le code n’est pas couplé à une implémentation précise : le jour où tu changes de librairie de log, pas besoin de tout refactorer, victoire.
PSR-3 prévoit aussi un système de placeholders dans les messages ({placeholder}), remplacés par les valeurs du contexte fourni . Pratique pour éviter de concaténer des strings en dur dans les logs. Et bonus : l’interface s’accompagne de quelques utilitaires comme Psr\Log\LogLevel
(une classe avec les constantes de niveaux) et un NullLogger (logger poubelle qui ne fait rien, pour ceux qui veulent désactiver les logs proprement) .
PSR-3, c’est un peu le coach thérapeutique des devs PHP. Il t’encourage à verbaliser tes problèmes (sous forme de messages de log) plutôt que de tout garder pour toi. Est-ce que ça rend ton code plus propre ? Disons que ça évite surtout de réinventer la roue à chaque fois qu’on veut écrire un log. Et franchement, standardiser le logging c’est pas plus mal : avant PSR-3, chacun avait sa petite fonction logMeThat($msg) perso dans un coin. Maintenant, plus d’excuse, tu fais ->info() comme tout le monde et tu restes calme. Jordi Boggiano (Mr Composer) est d’ailleurs l’éditeur de cette PSR , on peut donc remercier la communauté d’avoir confié le journal intime du PHP à quelqu’un de confiance. Allez, on respire, on loggue, et on passe à la suite.
PSR-4 : Autoloading 2.0
Après s’être occupé du style et des logs, revenons à un sujet plus architectural : le chargement automatique des classes, alias autoload. PSR-4, approuvée en 2014, est LA spécification moderne pour autoloader les classes PHP à partir des chemins de fichiers . En fait, elle remplace le vieux PSR-0 (le standard d’autoload originel) qui a été déclaré obsolète car un peu trop contraignant et vieillot . PSR-4 est plus souple, plus propre, bref le nouveau boss de l’autoload.
Le principe de PSR-4 est simple : on définit une correspondance entre un namespace de base et un répertoire de base. Ensuite, la structure des sous-namespaces reflète la structure des sous-dossiers, et le nom de la classe détermine le nom du fichier .php. Dit comme ça, c’est abstrait, prenons un exemple concret :
Supposons que dans ton fichier de config (par exemple le composer.json de ton projet), tu déclares que le namespace "MonAppli" correspond au dossier src/
. Du coup :
- La classe
MonAppli\Utils\Truc
devra se trouver dans le fichiersrc/Utils/Truc.php
. - La classe
MonAppli\Model\Bidule\Chose
ira danssrc/Model/Bidule/Chose.php
. - Et ainsi de suite. Chaque \ dans le namespace devient un / dans le système de fichiers. Magie !
PSR-4 précise également que les noms de classes sont sensibles à la casse (fini les casse-tête Windows vs Linux, tu respectes la casse partout) . Contrairement à PSR-0, les underscores _ n’ont plus de signification spéciale dans les noms de classes (sous PSR-0, un underscore simulait un séparateur de namespace à l’ancienne). En gros, PSR-4 dit : « Arrange tes dossiers selon tes namespaces et tout ira bien ».
Un petit exemple de configuration Composer pour illustrer ça :
{
"autoload": {
"psr-4": {
"MonAppli\\": "src/"
}
}
}
Avec ce réglage, si quelque part tu fais new \MonAppli\Controleur\Accueil()
, Composer (ou tout autoloader PSR-4) saura automatiquement qu’il doit inclure le fichier src/Controleur/Accueil.php
(contenant la classe MonAppli\Controleur\Accueil
). Plus besoin de dizaines de require_once écrits à la main partout. On définit la règle, et l’autoloader se charge du boulot.
La PSR-4, c’est un peu le Marie Kondo du PHP – elle te force à ranger tes fichiers bien comme il faut, et en échange, elle promet que ton code « t’apportera de la joie » (ou au moins moins d’erreurs d’inclusion). Les projets modernes en PHP adoptent quasi tous PSR-4 : Composer l’a intégré nativement, donc tu respectes PSR-4 sans même le savoir quand tu utilises Composer pour charger tes classes. Et si jamais tu repenses avec nostalgie à l’autoload PSR-0, dis-toi que PSR-4 est juste mieux fichu (plus besoin de nommer les classes Truc_SousTruc
pour refléter l’arborescence). On vit dans le futur, rangeons nos classes de manière PSR-4 et arrêtons de pleurer le passé.
PSR-7 : HTTP message interfaces
On arrive à PSR-7, standard approuvé en 2015, qui a fait couler pas mal d’encre (ou de pixels). PSR-7 définit une série d’interfaces pour représenter les messages HTTP (requêtes et réponses) de façon universelle . En gros, au lieu d’avoir chaque framework avec sa classe Request maison incompatible avec celle du voisin, le PHP-FIG a dit : « On va créer LA façon commune de gérer une requête et une réponse HTTP en PHP ». Dit comme ça, super ambitieux.
PSR-7 introduit 7 interfaces principales :
- MessageInterface – la base pour tout message HTTP (contient les méthodes pour les headers, le corps, la version HTTP…).
- RequestInterface – pour les requêtes client -> serveur (hérite de MessageInterface, ajoute la méthode HTTP, l’URI cible, etc.).
- ResponseInterface – pour les réponses serveur -> client (hérite de MessageInterface, ajoute le status code et le reason phrase).
- ServerRequestInterface – une requête côté serveur, qui étend RequestInterface en ajoutant tout ce qu’il faut pour gérer les données de l’environnement serveur (GET/POST, cookies, fichiers uploadés, etc.).
- StreamInterface – pour manipuler le corps du message via un flux (lecture/écriture).
- UriInterface – pour représenter et manipuler l’URL (chemin, host, schéma…).
- UploadedFileInterface – pour représenter un fichier téléchargé (via un formulaire, par ex), avec son nom, type, taille, etc., et permettre son déplacement.
Ouf, ça en fait du monde ! En pratique, tu n’implémentes pas ça toi-même à la main (sauf si tu aimes souffrir), tu utilises une bibliothèque qui fournit des classes concrètes implémentant ces interfaces (par ex. Guzzle HTTP, Laminas Diactoros, Slim PSR-7…). L’intérêt, c’est que si tout le monde utilise ces interfaces, tu peux échanger les composants (middleware, clients HTTP, frameworks) plus facilement.
Un aspect clé (et polémique) de PSR-7 : elle insiste sur l’immutabilité des objets Request/Response. Toutes les méthodes qui modifient quelque chose (par ex withHeader(), withStatus()…) ne changent pas l’objet courant mais retournent une nouvelle instance modifiée. L’idée est d’éviter les effets de bord imprévus en cours de route. C’est joli sur le papier fonctionnel, mais devine quoi ? Symfony (via son composant HttpFoundation) faisait tout l’inverse depuis des lustres – des requêtes modifiables à foison. Du coup, PSR-7 a provoqué un sérieux débat, car elle demandait à Symfony de renier sa philosophie ou de faire un pont tordu entre les deux mondes . Au final, Symfony a créé une couche d’adaptation pour convertir ses Request/Response en PSR-7 et vice-versa . Ambiance « on fait la grimace mais on s’adapte ». Preuve que même une Recommandation Standard peut se heurter aux réalités du terrain.
Voyons rapidement comment on pourrait utiliser PSR-7 dans un code :
use Psr\Http\Message\ServerRequestInterface;
use Psr\Http\Message\ResponseInterface;
function greetUser(ServerRequestInterface $request): ResponseInterface {
$name = $request->getQueryParams()['name'] ?? 'toi';
// Créer une réponse (via une implémentation concrète, ex: GuzzleHTTP)
$response = new \GuzzleHttp\Psr7\Response();
$response->getBody()->write("Bonjour $name !");
return $response->withHeader('Content-Type', 'text/plain');
}
Ici, la fonction greetUser peut recevoir n’importe quelle requête implémentant ServerRequestInterface (que ça vienne de Zend Diactoros, Slim, etc.). On extrait un paramètre de query string name (via getQueryParams()), on crée une réponse PSR-7 (en utilisant Guzzle par exemple pour la classe concrète), on écrit dans le corps « Bonjour X ! », et on renvoie la réponse en ajoutant un header de type de contenu. Remarquez le petit $response->withHeader(...)
qui retourne une nouvelle instance de réponse avec le header ajouté, au lieu de modifier l’objet original – c’est l’immutabilité en action.
L’avantage de PSR-7, c’est que toutes les libs et frameworks qui l’adoptent parlent le même langage HTTP. Tu peux prendre un middleware de Slim, le brancher dans Zend Expressive (aujourd’hui Laminas), et ça marche, car ils manipulent tous des RequestInterface et ResponseInterface standard. On a enfin une brique commune dans l’écosystème pour tout ce qui touche aux requêtes/réponses HTTP .
PSR-7, c’est un peu la révolution copernicienne qu’on a voulu imposer à tous, avec ce slogan : « Désormais, la Terre (le code) tournera autour du Soleil (PSR-7) ! ». Sauf que certains avaient déjà leur propre système solaire (coucou Symfony) et ont un peu grincé des dents. On peut voir PSR-7 comme un standard brillant mais exigeant, qui a nécessité des concessions. Heureusement, il a ouvert la voie à un écosystème de middlewares et de micro-frameworks hyper cool. Et puis bon, admettons-le, manipuler ces objets immuables, ça donne l’impression d’être un puriste de la propreté du code – un petit frisson hype pas désagréable pour les développeurs en mal de design pattern.
PSR-11 : Container Interface
On change de registre avec PSR-11, approuvée en 2017, qui standardise l’interface des containers d’injection de dépendances. Dit simplement, un container c’est cette boîte magique où on enregistre nos instances de services, et qu’on interroge pour obtenir tel ou tel objet dont on a besoin. Chaque framework avait sa façon de faire, PSR-11 a dit : « fini le bazar, on va tous utiliser la même interface pour nos conteneurs » .
ContainerInterface, défini par PSR-11, est d’une simplicité biblique : deux méthodes seulement ! Un get($id)
pour récupérer un objet à partir d’un identifiant (généralement le nom ou classe du service), et un has($id)
pour vérifier si le service existe dans le conteneur . C’est tout. Pas de méthode pour ajouter ou configurer des entrées – la PSR-11 se concentre uniquement sur l’utilisation du container, pas sur sa construction. Pourquoi ? Parce que chaque conteneur (Symfony, Laravel, PHP-DI, etc.) a ses propres recettes pour enregistrer les services (fichiers de config YAML, annotations, autowiring…). Standardiser ça aurait été mission impossible ou trop restrictif. Alors ils ont choisi le plus petit dénominateur commun : comment fetcher une dépendance de manière uniforme .
Un petit exemple pour la route :
use Psr\Container\ContainerInterface;
function utiliseCache(ContainerInterface $container) {
if ($container->has('cache')) {
$cache = $container->get('cache');
$cache->clear(); // On appelle une méthode du service cache
}
}
Ici, on ne sait pas si on nous a refilé un container Symfony, Laravel, Pimple ou autre chose implémentant ContainerInterface. On s’en fiche : on peut appeler ->has('cache')
et ->get('cache')
de manière standard. Le code sera compatible tant que le conteneur suit PSR-11. Pour info, Symfony’s DependencyInjectionContainer, Laravel’s container, PHP-DI, etc., tous implémentent désormais PSR-11 (soit nativement, soit via un adaptateur). Ça permet par exemple à une lib tierce de dire « donnez-moi n’importe quel conteneur PSR-11, je saurai m’en servir pour récupérer mes dépendances » .
Attention, PSR-11 a aussi ses détracteurs sur le plan philosophique : certains considèrent que d’utiliser le container directement dans le code (genre $container->get()
partout) c’est un anti-pattern (Service Locator), et qu’on devrait lui préférer l’injection de dépendances “pure” (via les constructeurs par exemple). D’ailleurs, le meta document de la PSR-11 le dit noir sur blanc : « on ne recommande pas de passer le container aux objets pour qu’ils aillent chercher eux-mêmes leurs dépendances » . Le container doit idéalement rester dans les coulisses (framework) et injecter ce qu’il faut où il faut, pas devenir omniprésent dans ton code métier.
PSR-11, c’est un peu comme standardiser la prise électrique pour tous les chargeurs de téléphone. Sur le papier, c’est super : plus de galère, tout le monde s’alimente pareil (ici tout le monde obtient ses objets pareil). Mais ça ne dit pas comment on fabrique l’électricité derrière (comment les instances sont configurées). Au moins, avec PSR-11, fini les conteneurs propriétaires ingérables : tu peux toujours dire “je fournis un ContainerInterface”, c’est passe-partout. Et si tu abuses du container partout, tes collègues viendront sûrement te rappeler (sarcastiquement) que *« oui, c’est standard, mais n’en fait pas ta béquille ! ». Bref, PSR-11 c’est la neutralité : juste ce qu’il faut pour brancher la prise, pas plus.
PSR-12 : Le guide de style étendu
Souvenez-vous de PSR-2, notre guide de style maniaque. Eh bien PSR-12, validée en 2019, est venue l’étendre, l’expanser et la remplacer . En effet, entre 2012 et 2019, PHP a beaucoup évolué (arrivée de PHP 7, de nouvelles syntaxes, etc.), donc il fallait mettre à jour les règles de style pour coller à l’époque moderne. PSR-12 reprend toutes les règles de PSR-2, et y ajoute des précisions pour les nouveautés de PHP et quelques durcissements de ton.
Qu’est-ce que PSR-12 a de plus que sa maman PSR-2 ? Quelques exemples notables :
- Elle exige d’écrire
<?php declare(strict_types=1)
; en tête de file sur sa propre ligne, si on active le mode strict . Un petit coucou à la directive declare qui a désormais droit de cité dans le style. - Elle permet (et régit) la syntaxe de regroupement des importations. Par exemple, on peut faire
use Mon\Namespace\{ClasseA, ClasseB, ClasseC as C}
; sur une seule ligne . PSR-2 ne couvrait pas ce cas, PSR-12 le fait. - Elle demande que les alias de types scalaires soient en minuscule courte (int au lieu de integer, etc.) . Histoire d’uniformiser même ça.
- Elle clarifie aussi des choses sur les visibilités de constantes de classe (introduites en PHP 7.1) : en gros, maintenant tu dois mettre public const au lieu de juste const si tu veux être explicite, etc. (C’est dans PSR-12 que ça a été mentionné de façon plus formelle).
- Idem pour le type void ou le trailing comma possible dans les appels de fonctions multidignes – PSR-12 en parle, PSR-2 ne pouvait pas (ça n’existait pas encore à l’époque).
En résumé, PSR-12 est un superset de PSR-2 qui adapte le style de code aux réalités de PHP 7+ et même 8. Elle est devenue la référence actuelle pour tout l’outillage (PHP_CodeSniffer et consorts l’intègrent par défaut maintenant, en lieu et place de PSR-2).
Un petit exemple de code qui illustre l’esprit PSR-12 :
<?php
declare(strict_types=1);
namespace MonProjet\LeFutur;
use MonProjet\Truc\{Tool, Utilisateur as User};
use function MonProjet\Utils\helperFunction;
class MaNouvelleClasse extends MaAncienneClasse implements MonInterface
{
public function traiteDonnee(int $valeur): ?string
{
if ($valeur === 0) {
return null;
}
// Autre traitement...
return (string) $valeur;
}
}
On y voit : la déclaration strict_types
en haut (imposée sur sa propre ligne), l’usage du grouping dans les use (plusieurs classes importées depuis MonProjet\Truc{…}), le type hint int et le return type ?string collés sans espace avant les deux-points (règle PSR-12 oblige), etc. Visuellement, ça reste proche de PSR-2 mais c’est mis à jour aux nouveautés syntaxiques.
On pourrait dire que PSR-12, c’est la version director’s cut de PSR-2 – plus longue, plus complète, pour les vrais fans du détail. Certains développeurs grognons diront « Pff, encore des règles, toujours des règles ». Mais avouons que c’est pratique d’avoir une référence à jour. Et puis bon, on peut en rire : PSR-12 a même standardisé l’art d’écrire une liste d’use dans le bon ordre, si ça ce n’est pas du perfectionnisme… On imagine les réunions enflammées du PHP-FIG pour décider s’il faut une ligne vide entre tel et tel block. Oui, c’est arrivé. Mais ne tirons pas trop sur l’ambulance : grâce à ces maniaques, on a des codebases plus homogènes. Un dev expérimenté suivra probablement déjà 90% de PSR-12 sans s’en rendre compte (à force, on a intégré ces conventions). Les 10% restants serviront de sujet de blague au prochain meetup (« Alors, t’as mis ta ligne vide après ton declare(strict_types=1) ou quoi ? »).
Autres PSR notables en vrac
La liste des PSR ne s’arrête pas à 12, et d’autres recommandations méritent un petit clin d’œil, soit parce qu’elles sont utiles, soit parce qu’elles sont… particulières. En voici quelques-unes supplémentaires, sur le ton léger bien sûr :
- PSR-0 : Autoloading Standard (le précurseur) – L’ancêtre de PSR-4, désormais déprécié. Il imposait des règles d’autoload où les underscores dans les noms de classes correspondaient à des séparateurs de dossier, etc. C’était bien pour son époque, mais on l’a envoyé à la retraite au profit de PSR-4 . Repose en paix, PSR-0, on te garde un petit souvenir ému dans les vieux projets.
- PSR-5 : PHPDoc Standard – Une tentative de standardiser la documentation PHPDoc. Toujours en draft (jamais acceptée officiellement) . Oui, vous avez bien lu, la doc c’est tellement fun que depuis 2014 ce PSR se traîne comme un marronnier. On voulait formaliser tous les tags PHPDoc, couvrir les nouveautés du langage, etc. Peut-être qu’un jour on y arrivera. En attendant, chacun fait un peu comme il le sent côté commentaires, et personne ne s’en plaint trop – sauf quand PhpStorm râle.
- PSR-6 : Caching Interface – Standard de 2015 pour la gestion de cache. Il définit deux interfaces principales, CacheItemInterface et CacheItemPoolInterface, pour manipuler des éléments de cache de façon générique . En gros, on peut créer des libs qui utilisent un cache sans savoir si derrière c’est du Redis, du Memcached ou un vieux fichier. PSR-6 est assez complet (système d’objets de cache avec méthodes
getItem()
,set()
,isHit()
,save()
… et gestion d’expiration). Symfony Cache et d’autres l’implémentent. C’est bien, mais un peu verbeux pour des petits usages. - PSR-16 : Simple Cache – Arrivé en 2018, il propose une interface de cache simplifiée . Plutôt que tout le cérémonial de PSR-6, ici c’est une approche key-value très directe : interface CacheInterface avec des méthodes
get($key)
,set($key, $value)
,delete()
, etc., inspirée de l’API cache de FIG simple. Parfait pour les besoins basiques où PSR-6 paraissait sortir l’artillerie lourde. On peut voir PSR-16 comme le petit frère pragmatique de PSR-6. - PSR-8 : Huggable Interface – Ah, celle-là, il faut en parler : c’est une PSR… imaginaire (et abandonnée) qui définissait une interface pour… faire des câlins (hug) entre objets . Oui, un pur poisson d’avril du PHP-FIG. Elle n’a jamais été sérieuse, mais elle figure dans la liste avec un statut “Abandoned”. Preuve que même les architectes sérieux de FIG ont de l’humour (absurde) : « établir un moyen commun pour les objets d’exprimer leur appréciation mutuelle en se faisant des hugs », qu’ils disaient. On n’est pas passé loin d’avoir un
$obj1->hug($obj2)
standard… - PSR-13 : Hypermedia Links – Standardise la représentation des liens hypermédia (des interfaces Link pour manipuler des URLs, rel, attributs… ) . Utile dans les APIs REST HAL, JSON-LD et cie. Pas le plus connu des devs lambda, mais sachez qu’il existe.
- PSR-14 : Event Dispatcher – Approuvé en 2019, il définit comment dispatcher des événements et y attacher des listeners de manière commune . En gros, un équivalent du pattern Observateur, standardisé. Symfony a son EventDispatcher depuis longtemps, Laravel ses Events, etc. PSR-14 essaie de les faire se tenir la main. À voir si l’adoption suivra, mais c’est intéressant pour des libs intermédiaires voulant balancer des events sans lier à un implémentation précise.
- PSR-15 : HTTP Server Request Handlers (Middlewares) – Complément de PSR-7, celui-ci (2017) standardise les middlewares HTTP côté serveur . Il définit deux interfaces : RequestHandlerInterface (quelque chose qui prend une ServerRequestInterface et renvoie une ResponseInterface) et MiddlewareInterface (quelque chose qui prend une requête, la traite ou la modifie, puis soit renvoie une réponse, soit délègue au handler suivant). Ça permet de composer des middlewares interchangeables entre frameworks (Slim, Mezzio/Laminas, etc., utilisent PSR-15 à fond). En gros, PSR-7 + PSR-15 = tu peux te faire ton propre mini-framework modulaire en empilant des middlewares de diverses provenances. Plutôt cool pour les fans de pipelines HTTP.
- PSR-17 : HTTP Factories – Standard de 2018 pour la création d’objets PSR-7 via des fabriques . Parce que oui, créer une Request ou un Stream PSR-7 pouvait être spécifique à chaque lib. PSR-17 dit : « fournissez des FactoryInterfaces (RequestFactory, ResponseFactory, StreamFactory, etc.) afin de pouvoir créer ces objets de manière agnostique ». Utile en coulisses pour les frameworks ou pour PSR-15 justement, afin de ne pas dépendre d’une implé implémentation concrète particulière.
- PSR-18 : HTTP Client Interface – Le pendant client HTTP (approuvé en 2019) qui définit une interface ClientInterface avec une méthode
sendRequest(RequestInterface $request)
: ResponseInterface . L’objectif : pouvoir remplacer facilement notre client HTTP (cURL, Guzzle, etc.) sans changer notre code métier. Si on code une librairie qui fait des appels HTTP, on peut accepter n’importe quel client PSR-18 en entrée. Pratique pour les tests (mock de client) et pour offrir le choix de l’outil HTTP à l’utilisateur de ta lib. Avec PSR-18, on complète la famille HTTP : PSR-7 (message), PSR-17 (fabrique), PSR-15 (middleware serveur), PSR-18 (client).
On s’arrête là pour le tour d’horizon ! Comme vous le voyez, les PSR couvrent désormais un large spectre de sujets dans l’écosystème PHP. On a même un PSR-20 (Clock) qui a été récemment accepté pour standardiser l’accès à l’horloge (genre pour la tester facilement).
Le mot de la fin
Alors, ces standards PHP, révolution ou poudre aux yeux ?. D’un côté, les PSR ont clairement amélioré la vie des développeurs PHP en alignant nos violons : fini les guerres de style (bon, OK, presque finies…), fini les autoloads incompatibles, fini les mille et une façons d’injecter un service ou de logger un truc. L’interopérabilité a fait un bond en avant, et PHP a gagné en maturité grâce à ces recommandations suivies massivement . On peut coder dans Laravel le matin, faire du Symfony l’après-midi, et on n’est pas totalement dépaysé parce que la base du code est familière (merci PSR-1/2/12). C’est un fait.
D’un autre côté… quelle ironie de voir un langage autrefois qualifié de “foireux” par les puristes devenir l’un des plus normés ! Le FIG a beau dire que ce ne sont que des recommandations, la pression communautaire fait que si tu ne les suis pas, tu passes un peu pour la tanche la moins oxygénée de la rivière. Qui oserait aujourd’hui sortir un gros projet open-source PHP en mettant ses accolades n’importe comment ou en ignorant PSR-4 ? À tes risques et périls de te faire huer sur X par les ayatollahs du code style. Il y a même un adage moqueur qu’on pourrait appliquer : « L’avantage des standards, c’est qu’il y en a tellement parmi lesquels choisir ». PHP a désormais les siens, et gare à celui qui en invente un 23e pour faire son intéressant.
Au final, on peut en rire : les PSR, c’est un peu la Convention de Genève du développeur PHP. On s’est mis d’accord pour ne plus se torturer mutuellement avec du code immonde, on a signé les accords (en gros, on a cliqué “phpcs –standard=PSR12” dans nos IDE) et on essaye de s’y tenir. Évidemment, comme toute convention, il y a les frondeurs et les tatillons. Certains vont chipoter sur la moindre déviation (le chasseur de trailing space, on le connaît tous), d’autres vont coder en cowboy façon 2005 en disant « vos PSR, j’en fais du compost ». Mais globalement, le bénéfice est là : on se comprend mieux entre devs PHP, on partage des packages sans trop se battre, bref on a un langage commun au-delà du langage PHP lui-même.
Les PSR ont apporté de la discipline dans le chaos qu’était PHP à ses débuts, sans (trop) tuer la créativité. On peut toujours coder comme on l’entend à l’intérieur des fonctions, mais au moins sur la forme externe, on parle la même langue. Et si tout ça vous paraît bien sérieux, rappelez-vous qu’ils ont quand même essayé de nous faire gober une interface de câlins (PSR-8) – preuve qu’il reste de l’humour et de l’absurde dans ce monde de conventions.