Aller au contenu principal

Qualité de code : le quatuor infernal PHPStan, Rector, CS Fixer, Biome

Ne laissez plus passer de bugs. Découvrez ma configuration Level Max pour PHPStan, Rector, CS Fixer et Biome.

Publié le

Temps de lecture 4 min

La dette technique n'est pas une fatalité. C'est souvent juste un manque d'outillage. J'ai mis en place une pipeline de qualité drastique. Pas pour me flageller, mais pour déléguer la rigueur à des machines.

Voici mes quatre gardiens du temple.

PHPStan : l'analyse statique (niveau max ou rien)

L'époque où l'on découvrait une NullPointerException en production parce qu'un utilisateur avait un email vide est révolue. Ou du moins, elle devrait l'être.

Sur ce blog, j'ai activé le mode "paranoïaque" de PHPStan : Level Max. Au début, ça fait mal. Vous lancez l'outil, et il vous insulte avec 400 erreurs rouges. "Call to a member function getTime() on null", "Method expects User, User|null given".

Votre premier réflexe ? "C'est bon, je sais que ça ne sera pas null ici !". Spoiler : Vous avez tort.

La réalité, c'est que PHPStan a raison. Si il existe une infime chance qu'une variable soit nulle, le bug arrivera.

Voici ma configuration de combat dans phpstan.neon :

YAML
parameters:
    level: max
    paths:
        - src
    # On force le traitement des PHPDoc comme incertain
    # Ca nous oblige à typer proprement en PHP natif
    treatPhpDocTypesAsCertain: false 

Rector : l'architecte de la modernisation

Migrer vers PHP 8.4 manuellement ? Jamais de la vie. Rector est mon outil de "Refactoring Automatique". C'est un robot qui lit l'AST (Abstract Syntax Tree) de votre code et applique des règles de transformation.

Exemple concret : sur Lecodeestdanslepre, j'ai lancé Rector avec le set UP_TO_PHP_84. En 30 secondes, il a transformé mes propriétés en readonly, remplacé mes fonctions anonymes par la syntaxe (...) =>, et nettoyé le code mort.

Mais attention, il faut le dompter. J'ai dû exclure certaines règles dans rector.php pour éviter qu'il ne casse mes constructeurs Doctrine.

PHP-CS-Fixer : le tyran du style

Si Rector est l'architecte, PHP-CS-Fixer est le décorateur d'intérieur maniaque. Son job n'est pas de changer la logique, mais de s'assurer que chaque virgule est à sa place.

Sur ce projet, il n'est pas là pour faire joli. Il optimise :

PHP
// .php-cs-fixer.dist.php

$config->setRules([
    // Force le mode strict partout (PHP 7+)
    'declare_strict_types' => true,
    
    // Performance : Ajoute un \ devant les fonctions natives
    // \strlen() est plus rapide que strlen() car PHP ne cherche pas dans le namespace courant
    'native_function_invocation' => ['include' => ['@compiler_optimized']],
    
    // Risky rules : On autorise les fix qui modifient le code
    '@Symfony:risky' => true,
]);

Grâce à lui, je ne débat plus jamais de "où mettre l'accolade" en Review. C'est automatisé.

Biome : la révolution Rust

Côté JS, c'était le chaos avec ESLint et Prettier. J'ai tout viré pour Biome.

Pourquoi ? Parce que c'est écrit en Rust. La différence de vitesse est telle qu'on croit que la commande a planté. Checked 45 files in 4ms. Attendez, 4 millisecondes ? Oui.

Et le meilleur ? Sur ce projet, je n'ai même pas installé Node.js. J'utilise le package Composer kocal/biome-js-bundle. Il télécharge le binaire Biome (comme AssetMapper le fait pour Tailwind) et me permet de lancer mes checks directement depuis PHP.

Bash
composer require --dev kocal/biome-js-bundle

Pas de node_modules, pas de package.json. Juste un binaire ultra-rapide piloté par PHP.

Mon workflow : la discipline par Castor

Avoir des outils, c'est bien. Les utiliser, c'est mieux. Pour éviter le syndrome de l'oubli, tout est centralisé dans Castor, notre task runner moderne.

PHP
// .castor/qa.php
#[AsTask(description: 'Auto-fix all QA issues')]
function fix(): void
{
    io()->title('Auto-fixing all QA issues');
    // ...
    run('docker compose exec php vendor/bin/php-cs-fixer fix');
    run('docker compose exec php bin/biome check --write --unsafe assets/');
    run('docker compose exec php vendor-bin/rector/vendor/rector/rector/bin/rector process');
}

Je lance castor qa:fix avant chaque git push. C'est devenu un réflexe pavlovien. La machine nettoie derrière moi, et je peux me concentrer sur ce qui compte : la valeur métier.

Gestion des cookies

J'utilise Google Analytics, Google Tag Manager et Microsoft Clarity pour améliorer votre expérience. Vous pouvez choisir les services que vous autorisez.

Le code est dans la boîte !

Vous recevrez bientôt les nouveaux billets dans votre boîte mail. Pas de spam, promis.

Désinscription possible à tout moment.