Qualité de code, CodeSniffer et PSR

Mise en place d'un code sniffer pour appliquer les standards PSR

Le 04/11/2022
Par Matthieu

Pourquoi améliorer la qualité de son code ?

Lors de la création ou de l’évolution d’une application (web ou logiciel), la prise en compte de la qualité du code s’avère primordiale dans un contexte où les applications deviennent de plus en plus complexes et dont le code peut être utilisé par des équipes entières de développeurs.

L’un des aspects qualitatifs du code est la manière dont il est à proprement écrit. Reposant sur un langage spécifique (ici nous allons utiliser PHP mais cette approche peut s’appliquer à tous les autres langages de programmation), celui-ci demande de respecter une certaine nomenclature (propre à chaque langage bien que certaines notions peuvent être partagées). Certains langages sont plus restrictifs que d’autres, c’est-à-dire qu’ils nécessiteront d’être parfaitement écrit pour faire fonctionner le code. Dans le cas de PHP, ce n’est pas rigide (bien qu’il tente petit à petit à le devenir en s’inspirant des autres langages de programmation), la manière dont est écrit le code peut largement varier d’un développeur à un autre pour un résultat identique (je simplifie volontairement pour ne pas aborder les sujets d’optimisation de performances notamment). Par exemple, dans une équipe de développeurs, on peut se retrouver avec une multitude de façons d’écrire une condition if() :

Exemple de versions pour une même condition if() en PHP Exemple de versions pour une même condition if() en PHP

Harmoniser le code source permets de :

Des normes et règles de programmation ont été créées et acceptées par la communauté de développeurs du langage. C’est le cas de celle que nous allons mettre en place : PSR 🔗

Les standards de programmation selon PSR

PSR, pour PHP Standards Recommandations, est géré par un groupe de développeurs de frameworks dont l’objectif est de proposer des standards de programmation depuis 2009 applicable à n’importe quel projet PHP. Chaque membre peut proposer de nouvelles règles qui seront par la suite étudiées puis mises au vote avant d’être adoptées ou non.

L’ensemble des recommandation sont regroupées par contextes d’application: normes de codage de base (PSR-1 Basic Coding Standard), standard de chargement automatique (PSR-4 Autoloading Standard), client HTTP (PSR-18 HTTP Client)

Chaque recommandation fait l’objet d’un suivis et possède un statut indiquant si elle s’applique, si elle tends à disparaitre ou si elle n’est plus appliquée.

Pour connaitre le statut des recommandations PSR : par ici 🔗

Validation et correction du code avec PHP CodeSniffer

Le respect des recommandation PSR (principalement PSR-1 et PSR-12 pour les règles de nomenclature) peut rapidement se compliquer et devenir chronophage, si cela est fait manuellement, lorsque le projet PHP possède un grand nombre de fichiers et une structure complexe.

Heureusement, les développeurs peuvent utiliser un outils qui va analyser, valider et corriger le code en fonction des standards de programmation : les code sniffer.

Cet outils va parcourir l’ensemble des fichiers, analyser sa structure et vérifier que les standards de programmation sont respectés. Dans le cas contraire l’outils se charge de remonter les erreurs et d’afficher la règle qui n’est pas respecté. Il est de plus possible d’appliquer directement une correction aux fichiers concernés.

L’analyse ne se limite pas exclusivement aux fichiers PHP, elle peut s’appliquer à de nombreux autres langages comme le CSS ou encore le JS qui possèdent aux aussi des standards de programmation.

Si de base les code sniffer s’appuient sur les standards de programmation comme PSR ou PEAR, il est possible d’y appliquer des règles personnalisées. C’est ce que propose le package de Squizlabs que j’ai utilisé pour mon site : PHP_CodeSniffer 🔗 

Utiliser PHPCS dans un environnement de développement

L’utilisation des code sniffer va principalement dépendre de l’environnement de développement du développeur mais auront en commun l’utilisation de deux fichiers spécifiques :

L’installation se fait via le gestionnaire de package Composer soit sur un projet spécifique soit de manière globale sur le système d’exploitation.

composer global require "squizlabs/php_codesniffer=*"

Une fois installé, il sera possible d’appeler une commande via le terminal afin de lancer l’analyse ou d’appliquer la correction :

// Lance l'analyse du fichier file.php
phpcs file.php

// Corrige le fichier file.php
phpcbf file.php

De nombreuse options peuvent être appliquées à la commande afin de cibler des fichiers en particuliers ou d’appliquer des standards de programmation spécifiques.

Afin de simplifier cette gestion et de ne pas réécrire les options à chaque fois que l’on veut utiliser le code sniffer, il est possible de définir un fichier XML qui contiendra l’ensemble des options et des règles à prendre en compte : phpcs.xml

Pour voir le fichier phpcs.xml utilisé sur ce site : par ici 🔗

Comme vous pouvez le voir sur le fichier ci-dessus, il est spécifié que le code sniffer ne s’appliquera qu’a certain dossiers du projet (définis dans une balise <file>) en excluant certains dossiers respectant un schéma d’accès (balise <exclude-pattern>) et en appliquant les standards du PSR-1 et du PSR-12 (balise <ref>). In fine lorsque je lance la commande phpcs depuis mon terminal, l’analyse respectera ces options.

Pour aller un peu plus loin : déclencher le code sniffer sur les événements GIT

Afin d’optimiser ce processus, il est possible de déclencher les commandes phpcs et phpbcf lorsqu’un événement Git (gestionnaire de versions) survient.

Pour cela, il suffit de d’utiliser le système de hook proposé par GIT : dans le dossier caché .git/hooks créer un nouveau fichier appelé pre-commit (sans extension) et le rendre exécutable via le terminal avec la commande suivante : chmod +x .git/hooks/pre-commit

Le fichier contiendra le code suivant :

#!/bin/sh

STAGED_FILES=$(git diff --cached --name-only --diff-filter=ACM | grep ".php\{0,1\}$")

if [[ "$STAGED_FILES" = "" ]]; then
  exit 0
fi

PASS=true

echo "\nValidating PHPCS:\n"

# Check for phpcs
which phpcs &> /dev/null
if [[ "$?" == 1 ]]; then
  echo "\t\033[41mPlease install PHPCS\033[0m"
  exit 1
fi

RULESET=./phpcs.xml

for FILE in $STAGED_FILES
do
  phpcs --standard="$RULESET" "$FILE"

  if [[ "$?" == 0 ]]; then
    echo "\t\033[32mPHPCS Passed: $FILE\033[0m"
  else
    echo "\t\033[41mPHPCS Failed: $FILE\033[0m"
    PASS=false
  fi
done

echo "\nPHPCS validation completed!\n"

if ! $PASS; then
  echo "\033[41mCOMMIT FAILED:\033[0m Your commit contains files that should pass PHPCS but do not. Please fix the PHPCS errors and try again.\n"
  exit 1
else
  echo "\033[42mCOMMIT SUCCEEDED\033[0m\n"
fi

exit $?

Ainsi lorsque l’on lancera la commande git commit , le script ci-dessous lancera le code sniffer qui utilisera le fichier de configuration phpcs.xml

Le tutoriel complet est accessible ici 🔗