Pourquoi est-ce important de respecter les standards de qualité ?
Le choix d'utiliser un framework professionnel comme Symfony traduit votre volonté de développer de meilleures applications. Ce chapitre est l'occasion d'aborder un sujet important : la qualité de code !
Le premier niveau de qualité de code est celui de la conformité avec des standards : le code est-il correctement formaté, facile à lire et à comprendre par d'autres développeurs ?
L'uniformisation simplifie le travail en équipe
On imagine souvent le développeur, la développeuse comme une personne assez asociale qui interagit très peu avec son entourage et pourtant rien n'est moins vrai.
Sur la plupart des projets Symfony, il est commun de travailler avec plusieurs autres développeurs, sans compter un chef de projet, un designer ou encore le client.
Le premier contrat social que l'on établit souvent dans une équipe, lorsque l'on démarre un nouveau projet informatique, est celui de l'uniformisation du code, autrement dit "la définition des standards".
Il permet à chaque développeur de reprendre facilement ou de relire le travail d'un autre développeur sans se préoccuper des questions "esthétiques" :
La parenthèse doit-être elle mise après un saut de ligne ou pas ?
Doit-on utiliser le camelCase ou le snake_case pour nommer nos variables et noms de classes ?
Ces questions sont complexes, car il n'y a pas de meilleures réponses (le débat entre camel case et snake case est d'ailleurs très célèbre dans le monde logiciel :p) et le langage PHP ne décrit aucun standard de développement.
Un standard facilite l'accès à un nouveau projet
Les PSR (pour "Propose a Standard Recommandation") sont l'ensemble des recommandations validées par le PHP Fig ("PHP Framework Interoperability Group") dont le rôle est d'améliorer l'interopérabilité entre les frameworks PHP.
Cette organisation regroupe l'essentiel des représentants des plus gros frameworks, CMS et librairies de l'écosystème PHP, dont le projet Symfony.
Actuellement, ces recommandations tiennent lieu de standards établis avec l'accord de ces représentants, donc une grande majorité des développeurs utilisant ces projets ont connaissance de ces standards.
Respecter les standards dans son projet facilite donc l'intégration d'un nouveau développeur, puisqu'il aura déjà connaissance des contraintes et règles à respecter.
Les standards sont appliqués sur les plus gros projets open source
Que ce soit Symfony, Laravel, Drupal ou même PrestaShop, ces projets respectent les quatre premières recommandations du PHP-FIG :
les conventions minimales de codage (PSR-1) ;
le style et l'organisation du code (PSR-12) ;
un contrat commun sur le logger (PSR-3) ;
un contrat commun sur le chargement des classes PHP (PSR-4).
Appliquez les bonnes pratiques de développement Symfony
Le framework Symfony est très attaché aux standards recommandés et fournit un support natif ou optionnel pour de très nombreuses recommandations.
En tant que développeur, si vous n'êtes pas impliqué dans le développement d'une librairie ou d'un projet réutilisable, il n'est pas indispensable de toutes les connaître, mais il faudra maîtriser au minimum les deux premières que nous allons parcourir en détail.
Les conventions minimales de codage : PSR-1
Cette recommandation définit un ensemble de règles basiques que devrait respecter l'ensemble des fichiers PHP de vos projets.
Vos fichiers doivent impérativement utiliser
<?php
ou<?=
.Vos fichiers doivent impérativement être encodés en UTF-8 sans BOM pour le code PHP.
Vos fichiers doivent soit déclarer des classes ou des fonctions, soit avoir des effets de bord (comme générer un affichage, stocker une configuration), mais ne doivent pas faire les deux en même temps.
Les noms d'espaces ("namespaces") et les classes doivent impérativement respecter une des recommandations de chargement de classes de la PSR (PSR-0 ou PSR-4).
Les noms de classes doivent impérativement être déclarés en StudlyCaps.
Les constantes de classes doivent impérativement être déclarées en majuscules.
Les noms de méthodes doivent impérativement être déclarés en camelCase.
Voici un exemple de fichier PHP qui respecte PSR-1 :
<?php
namespace OpenClassrooms\Exemple;
class SymfonyIsAwesome
{
const SYMFONY_VERSION = 4;
private function displayVersion() {
return self::SYMFONY_VERSION;
}
}
L'ensemble des bouts de code présentés ci-dessus respectent évidemment la PSR-1 (mais si ce n'est pas le cas, n'hésitez pas à nous faire un retour :ange:).
C'est quoi, l'UTF-8 sans BOM ? :euh:
UTF-8 est un encodage de fichier qui est compatible avec l'ensemble des systèmes d'exploitation et tous les navigateurs web. Il est utile si vous voulez éviter l'affichage de caractères mal interpr%tés par le navigateur de vos utilisateurs ! "Sans BOM" veut seulement dire que, contrairement à l'UTF-8 "standard", un caractère spécial ne sera pas utilisé en début de fichier. Ce caractère est parfois mal supporté par PHP et responsable d'une erreur assez connue et difficile à corriger :
Cannot modify header information – headers already sent by
Style et organisation du code : PSR-12
Cette spécification a pour objectif de réduire au maximum la difficulté de compréhension de code écrit par différents auteurs en définissant des règles d'écriture des différents éléments du langage PHP.
Elle contient donc une liste de règles à respecter sur le formatage du code PHP.
Le code doit impérativement respecter PSR-1.
Le code doit utiliser 4 espaces pour une indentation et non le caractère "tabulation".
Il n'y a pas de contrainte forte sur la longueur maximale d'une ligne, mais la PSR-2 recommande de ne pas dépasser les 120 caractères et conseille une longueur maximale de 80 caractères.
Il doit impérativement y avoir un saut de ligne après la déclaration du "namespace", et un saut de ligne après la déclaration du bloc des classes importées à l'aide de
use
.L'accolade ouvrante (
{
) doit impérativement se faire après un saut de ligne sur la déclaration de classe et sur la fermeture d'une classe (}
).La même règle s'applique pour la déclaration de fonctions et de méthodes de classe.
La visibilité doit être impérativement déclarée sur toutes les propriétés et méthodes de classe, les éléments de langage
abstract
etfinal
doivent impérativement être déclarés avant la visibilité, tandis que l'élément de langagestatic
doit être déclaré après la visibilité.Les structures de contrôle (if, else, foreach, par exemple) doivent être impérativement suivies d'une espace, l'appel de méthodes et de fonctions, non.
L'accolade ouvrante sur une structure de contrôle doit se faire impérativement sur la même ligne, et l'accolade fermante doit se faire sur la ligne suivante.
L'ouverture de parenthèses pour les structures de contrôle ne doit pas être suivie d'une espace, et la fermeture d'une parenthèse ne doit pas être précédée d'une espace.
Voici un exemple tiré de la spécification qui est compatible PSR-12 :
<?php
namespace Vendor\Package;
use FooInterface;
use BarClass as Bar;
use OtherVendor\OtherPackage\BazClass;
class Foo extends Bar implements FooInterface
{
public function sampleMethod($a, $b = null)
{
if ($a === $b) {
bar();
} elseif ($a > $b) {
$foo->bar($arg1);
} else {
BazClass::bar($arg2, $arg3);
}
}
final public static function bar()
{
//
}
}
Le premier exemple de ce chapitre n'est pas compatible PSR-12.
Saurez-vous deviner pourquoi ? ;)
Spécificités du projet Symfony
Les standards de code
Le projet Symfony respecte les recommandations PSR-1 et PSR-12 et dispose de son propre standard de code qui complète la PSR-12. Cette recommandation appelée "Symfony Coding Standards" est détaillée dans la documentation officielle.
Bien qu'il ne soit pas obligatoire de la respecter (il n'est d'ailleurs absolument pas obligatoire de respecter les PSR non plus !), la plupart des développeurs Symfony ont tendance à l'appliquer sur leurs projets personnels et professionnels.
Beaucoup plus stricts et exhaustifs que la PSR-12, ces standards définissent de nombreuses règles sur la structure du code, mais également sur les conventions de nommage de vos classes, variables ou éléments spécifiques du framework (comme la déclaration de services) ou encore sur la documentation.
Les bonnes pratiques de développement
En complément des standards de code, l'équipe Core du projet Symfony décrit un ensemble de bonnes pratiques pensées pour améliorer la productivité des développeurs lorsqu'ils utilisent le framework.
Ce document d'explication est composé de plusieurs catégories pour donner une vision pragmatique du développement d'applications, telle que l'imaginait son créateur Fabien Potencier.
Comment créer son projet ?
Comment organiser la configuration du projet ?
Comment organiser sa logique métier ?
Comment organiser et écrire ses contrôleurs ?
Comment organiser ses vues avec Twig ?
Comment écrire des formulaires ?
...
Lire l'ensemble de ces bonnes pratiques est utile, car elles sont de plus en plus utilisées sur les projets en entreprise, bien qu'à ce jour, il n'existe aucun outillage pour valider le respect des règles définies dans ce document.
Validez la qualité de votre application
Valider la qualité de son code est difficile manuellement et serait extrêmement chronophage à effectuer. Heureusement, il existe de nombreux outils et services capables d'effectuer la vérification, de remonter des erreurs et même - dans certains cas - de corriger les erreurs automatiquement !
Les outils de validation : linters et fixers
Dans l'écosystème PHP, nous retrouvons deux types d'outils pour vérifier la qualité du code et son adéquation avec les standards : les linters et les fixers.
Un "Code Linter" est un outil d'analyse statique de code source. Il sert à détecter des erreurs de syntaxe ou de non-respect d'un style ou d'une règle. Un "Code Fixer", quant à lui, est capable de corriger les erreurs automatiquement.
Le plus connu des linters est certainement celui fourni avec le langage PHP lui-même :
php -l <nom-de-fichier>
S'il y a la moindre erreur de syntaxe qui pourrait empêcher l'exécution du fichier PHP, le linter de PHP la trouvera !
Il existe également beaucoup de projets open source capables d'apporter de nombreuses informations sur la qualité du code PHP. La plupart sont configurables :
L'ensemble de ces outils peuvent être utilisés les uns en complément des autres pour vous permettre de contrôler la qualité de code de votre projet Symfony. Deux de ces projets sont recommandés dans le sens où ils disposent de configurations propres aux projets Symfony : PHP-CS Fixer et PHPStan.
Introduction à PHP-CS-Fixer
Originellement, ce projet a été créé pour corriger automatiquement la plupart des règles définies dans les recommandations des PSR-1 et PSR-2. Cet outil développé en PHP (et avec des composants Symfony !) est un exécutable utilisable en ligne de commande capable d'analyser un projet PHP en considérant un ensemble de règles configurables.
Une fois installé, il faut utiliser la commande "fix" de l'outil :
php php-cs-fixer.phar fix /chemin/vers/dossier-ou-fichier
Par défaut, ce sont les standards définis par PSR-1 et PSR-2 qui seront vérifiés et appliqués.
Cet outil est totalement configurable et capable de "corriger" l'essentiel des règles qui ne seraient pas respectées dans le code analysé. Par exemple, pour appliquer l'essentiel des règles définies dans les standards supplémentaires du projet Symfony, il suffit d'appliquer une règle supplémentaire.
php php-cs-fixer.phar fix /chemin/vers/dossier-ou-fichier --rules=@PSR1, @PSR12, @Symfony
Il existe énormément de règles déjà disponibles dans l'outil et il est possible de créer et d'intégrer ses propres règles en PHP.
Configuration de PHP-CS-Fixer
En plus de cela, l'ensemble des règles de vos projets peuvent être mises dans un fichier de configuration appelé .php_cs.dist. Si ce fichier existe à la racine de votre projet, il sera utilisé automatiquement par PHP-CS-Fixer. Le but de ce cours n'est pas de vous apprendre à écrire votre configuration, mais voici un exemple :
<?php
$enteteFichier = <<<COMMENT
Ceci sera ajouté dans tous vos fichiers PHP en entête.
(c) Léa <lea@openclassrooms.com>
A adapter et ré-utiliser selon vos besoins!
COMMENT;
$finder = PhpCsFixer\Finder::create()
->in(__DIR__)
->exclude('config')
->exclude('var')
->exclude('public/bundles')
->exclude('public/build')
// exclut les fichiers générés
->notPath('bin/console')
->notPath('public/index.php')
;
return PhpCsFixer\Config::create()
->setRiskyAllowed(true)
->setRules([
'@Symfony' => true,
'@Symfony:risky' => true,
'array_syntax' => ['syntax' => 'short'],
'header_comment' => ['header' => $enteteFichier, 'separate' => 'both'],
'linebreak_after_opening_tag' => true,
'mb_str_functions' => true,
'no_php4_constructor' => true,
'no_superfluous_phpdoc_tags' => true,
'no_unreachable_default_argument_value' => true,
'no_useless_else' => true,
'no_useless_return' => true,
'ordered_imports' => true,
'php_unit_strict' => true,
'phpdoc_order' => true,
'semicolon_after_instruction' => true,
'strict_comparison' => true,
'strict_param' => true,
])
->setFinder($finder)
->setCacheFile(__DIR__.'/var/.php_cs.cache')
;
Avec ce fichier de configuration, il n'est plus utile de passer un chemin en paramètre de la commande "fix" de l'outil : php php-cs-fixer.phar fix
.
Voici un exemple de retour de PHP-CS-Fixer :
➜ php php-cs-fixer.phar fix Loaded config default from ".php_cs". Using cache file "var/cache/.php_cs". ............................F...... Legend: ?-unknown, I-invalid file syntax, file ignored, S-Skipped, .-no changes, F-fixed, E-error 1) /var/www/html/src/Controller/Admin/BlogController.php (class_definition, return_type_declaration, trailing_comma_in_multiline_array) Fixed all files in 0.189 seconds, 10.000 MB memory used
Introduction à PHPStan
Acteur récent dans les outils d'analyse de code statique, l'outil PHPStan est capable de découvrir de très nombreux bugs dans vos projets et dispose d'une extension propre aux projets Symfony.
Cet outil ne va pas respecter l'adéquation de votre code avec les standards PSR, mais va parcourir le code de votre projet à la recherche de bugs. Par exemple, voici une liste des actions que PHPStan est capable de contrôler :
l'existence de classes et interfaces non importées, mais utilisées, à l'aide de
instanceof
,catch
, ou encore dans les définitions de vos méthodes ;l'existence des variables en prenant en compte la notion de visibilité ;
l'existence et la visibilité de toutes les méthodes et fonctions ;
l'adéquation des types assignés à vos propriétés ;
etc.
L'outil dispose de différents niveaux de contrôle, le niveau 0 étant le niveau de contrôle minimal et le niveau 8 le niveau de contrôle maximal à ce jour.
Une fois installé, l'outil - qui est un exécutable écrit en PHP - s'utilise de cette façon :
php phpstan.phar analyse /chemin/vers/dossier-ou-fichier
Par exemple, voici un fichier PHP d'exemple et le résultat de l'analyse de PHPStan :
<?php declare(strict_types = 1);
class HelloWorld
{
public function sayHello(DateTimeImutable $date): void
{
echo 'Hello, ' . $date->format('j. n. Y');
}
}
L'analyse de ce projet au niveau 7 retourne le résultat suivant :
------ ---------------------------------------------------------------------------------------------- Line data/results/1e/1e15947362a7cf15970d1aa3575c3a65/analyzed.php ------ ---------------------------------------------------------------------------------------------- 5 Parameter $date of method HelloWorld::sayHello() has invalid typehint type DateTimeImutable. 7 Call to method format() on an unknown class DateTimeImutable. ------ ---------------------------------------------------------------------------------------------- [ERROR] Found 2 errors
Il y a bien une erreur ! Le vrai nom de la classe est DateTimeImmutable.
Après correction, PHPStan ne trouve plus aucune erreur dans ce code : super !
[OK] No errors
En résumé
La qualité de code est un sujet compliqué qui peut parfois créer de la frustration ou du conflit dans une équipe.
Pourtant, il existe des standards de qualité qui définissent comment le code doit être organisé, écrit et formaté. Bien que non obligatoires, ces règles sont connues et respectées par une majorité de développeurs Symfony et généralement utilisées dans les projets.
En complément des PSR-1 et PSR-12, le projet Symfony a son propre standard de code que l'on peut décrire comme une extension de PSR-12. Le créateur de Symfony a aussi délivré un ensemble de bonnes pratiques de développement pour aider les développeurs à développer des applications de qualité tout en restant productifs.
Pour valider et contrôler la qualité de nos applications, il existe énormément d'outils gratuits et open source. On distingue les "linters", capables de remonter les erreurs des "fixers", capables de les corriger.
Dans cet écosystème riche, deux outils sont populaires et utilisés dans de très nombreux projets : PHP-CS-Fixer et PHPStan. Le premier contrôlera le respect des standards quand le second remontera des erreurs présentes dans votre code.
Dans le prochain chapitre, nous parlerons encore de qualité... mais cette fois de qualité fonctionnelle ! Il est temps d'apprendre à tester nos applications. :magicien: