Coder sans filet, vraiment ?
Dans le monde du développement PHP moderne, et particulièrement dans les projets Symfony, la qualité du code ne se mesure plus uniquement à l’exécution. L’analyse statique est permet de détecter des bugs, des incohérences de types et des mauvaises pratiques sans exécuter le code. C’est une pratique devenue incontournable pour toute équipe soucieuse de maintenabilité, de robustesse et de dette technique. Elle est le premier et le plus facile des filets de sécurité à mettre en place.
Cet article présente les principaux outils d’analyse statique et de qualité de code disponibles dans l’écosystème PHP, et explique comment les intégrer efficacement dans un projet Symfony.
Pourquoi l’analyse statique change vraiment la donne
Détection précoce des bugs
Un bug détecté lors de la phase de développement coûte infiniment moins cher qu’un bug détecté en production. L’analyse statique attrape :
- Les erreurs de types (
TypeErrorlatents) - Les accès à des propriétés ou méthodes inexistantes
- Les variables non initialisées
- Les code paths jamais atteints
- Les retours de fonction incompatibles avec leur signature
Documentation vivante du code
Annoter son code pour satisfaire un analyseur statique, c’est aussi documenter ses intentions. Un
@param non-empty-string $slug ou un type de retour précis comme array<int, User> vaut mieux que n’importe quel commentaire. Le code devient plus compréhensible et prévisible.Elle incite naturellement tous les développeurs à écrire du code en utilisant du typage strict et des PHPDoc précis.
Refactoring en confiance
Modifier une interface utilisée dans 40 services Symfony devient serein quand PHPStan vous dit immédiatement où vous avez cassé le contrat.
Uniformisation du code
Le code garde une uniformisation et une cohérence quelque soit les personnes qui interviennent sur le projet.
Automatisation naturelle
Ces outils s’intègrent parfaitement dans des outils de CI/CD comme GitHub Actions, GitLab CI ou autre. Un
exit code 1 bloque la merge request, point. Plus de mauvaises surprise lors de la mise en production.Ils sont aussi facilement utilisables avec des outils d’automatisation locaux tels que GrumPHP et CaptainHook qui viennent détecter dès qu’un commit est créer directement sur le poste du développeur.
Les outils de l’arsenal
PHP CS Fixer — le gardien du style
Site : cs.symfony.com
PHP CS Fixer analyse et corrige automatiquement votre code pour qu’il respecte les standards de style définis (PER-CS, Symfony coding standards…). Contrairement aux outils précédents, il ne cherche pas de bugs : il normalise la forme de votre code.
Installation
Configuration (.php-cs-fixer.php)
Utilisation
Ce que CS Fixer normalise
- Indentation, espaces, sauts de ligne
- Ordre et groupement des
use - Déclarations
strict_types - Casts, opérateurs, virgules trailing
- PHPDoc et annotations
Conseil : configurez CS Fixer dans votre éditeur (PhpStorm, VS Code) pour qu’il s’applique à la sauvegarde. Vos
git diff ne contiendront plus jamais de changements de style parasites.PHPStan — l’analyse statique de référence
Site : phpstan.org
Extensions : phpstan/phpstan-symfony phpstan/phpstan-doctrine
PHPStan est l’un des outils d’analyse statique les plus populaires de l’écosystème PHP. Son principe est simple : il analyse votre code PHP et détecte les erreurs sans avoir besoin de l’exécuter.
Installation
Configuration (phpstan.neon)
Les niveaux de rigueur (0 à 10)
PHPStan propose 11 niveaux de rigueur croissante. Le niveau 0 détecte les erreurs les plus grossières (appels à des méthodes inexistantes), le niveau 10 impose une typage quasi-total incluant les types génériques.
Ce que PHPStan détecte
------ -----------------------------------------------
Line src/Service/UserService.php
------ -----------------------------------------------
8 Method UserService::findUser() should return
App\Entity\User but returns App\Entity\User|null.
------ ----------------------------------------------
Baseline : apprivoiser un projet legacy
Sur un projet existant avec des centaines d’erreurs, la baseline vous sauve la mise :
Cela génère un fichier
phpstan-baseline.neon qui ignore les erreurs existantes. Il ne vous restera plus qu’à l’inclure dans votre fichier de configuration phpstan.neon :Vous pouvez ainsi introduire PHPStan sans bloquer votre CI, et résorber la dette progressivement.
Rector — bien plus qu’un outil de migration
Site : getrector.com
Extensions : tomasvotruba/type-coverage
Rector est souvent présenté comme un outil de migration (PHP 7 → 8, Symfony 5 → 6…), et il excelle effectivement dans ce rôle. Mais le réduire à ça serait passer à côté de sa valeur la plus immédiate : résorber la dette technique existante, indépendamment de toute montée de version.
Là où PHPStan signale les problèmes, Rector les corrige. Il analyse et transforme votre code via son AST (Abstract Syntax Tree), en appliquant des règles configurables à la granularité que vous choisissez.
Installation
Rector comme outil de réduction de dette — sans migration
C’est l’usage le plus sous-estimé de Rector. Vous pouvez l’utiliser exclusivement sur des sets de qualité de code, sans toucher aux versions de PHP ou Symfony :
Ces quatre sets s’appliquent à n’importe quelle version de PHP et de Symfony. Voici ce que Rector corrige automatiquement :
Code mort et simplifications :
Ajout automatique des types manquants :
Modernisation des constructions PHP (indépendante de la version cible) :
Quand activer les sets de migration
Une fois la dette de base résorbée, vous pouvez activer des sets de migration ciblés selon votre contexte. Par exemple, pour migrer les annotations Doctrine/Symfony vers les attributs PHP 8 :
Mode dry-run : toujours vérifier avant d’appliquer
Conseil de workflow : exécutez Rector en dry-run dans la CI pour que chaque merge request révèle le code qu’on aurait pu améliorer. Appliquez-le manuellement, en commits dédiés, pour garder un historique lisible et une revue de code sereine.
Levels : petit pas par petit pas
Les levels vous permettent de commencer la réécriture de votre code en par les règles les moins risquées. Ainsi en corrigeant niveau par niveau vous vous assurer de fusionner progressivement l’amélioration de votre code.
Rector Swiss Knife — la boîte à outils complémentaire
Repository : github.com/rectorphp/swiss-knife
Swiss Knife est un package de Rector qui fournit des utilitaires pratiques pour compléter améliorer la qualité de votre code sans les transformer en profondeur.
Installation
Fonctionnalités clés
Eviter d’avoir des restes de conflit Git dans le code :
Détecter les blocs de code commentés :
Finaliser les classes non étendues :
Vérifier que les fichiers ne contiennent qu’une seule classe :
S’assurer que le Namespace des Classes respecte l’arborescence :
Intégration dans un projet Symfony
Structure du projet
projet/ ├── .php-cs-fixer.php ├── phpstan.neon ├── phpstan-baseline.neon ├── rector.php └── composer.json
Utilisation avec Composer
{
"scripts": {
"cs-check": "php-cs-fixer fix --dry-run --diff",
"cs-fix": "php-cs-fixer fix",
"stan": "phpstan analyse",
"rector-check": "rector process --dry-run",
"rector-fix": "rector process",
"psr4-fix": "swiss-knife namespace-to-psr-4 src --namespace-root \"App\\\\\"",
"finalize-fix": "swiss-knife finalize-classes src tests",
"swiss-check": [
"swiss-knife check-conflicts .",
"swiss-knife check-commented-code src tests",
"swiss-knife find-multi-classes src"
],
"qa": [
"@cs-check",
"@stan",
"@rector-check",
"@swiss-check"
],
"fix": [
"@cs-fix",
"@rector-fix",
"@psr4-fix",
"@finalize-fix"
]
}
}
Les outils de qualité seront lancés avec la commande
composer qa.Pipeline CI/CD (GitLab CI)
stages:
- quality
variables:
COMPOSER_CACHE_DIR: "$CI_PROJECT_DIR/.composer-cache"
cache:
key: "${CI_COMMIT_REF_SLUG}"
paths:
- .composer-cache/
- vendor/
image: php:8.2-cli
before_script:
- apt-get update -yqq && apt-get install -yqq git unzip
- curl -sS https://getcomposer.org/installer | php -- --install-dir=/usr/local/bin --filename=composer
- composer install --no-progress --no-interaction
cs-check:
stage: quality
script:
- composer cs-check
rules:
- if: '$CI_PIPELINE_SOURCE == "merge_request_event"'
- if: '$CI_COMMIT_BRANCH'
phpstan:
stage: quality
script:
- composer phpstan
rules:
- if: '$CI_PIPELINE_SOURCE == "merge_request_event"'
- if: '$CI_COMMIT_BRANCH'
rector:
stage: quality
script:
- composer rector-check
rules:
- if: '$CI_PIPELINE_SOURCE == "merge_request_event"'
- if: '$CI_COMMIT_BRANCH'
swiss:
stage: quality
script:
- composer swiss-check
rules:
- if: '$CI_PIPELINE_SOURCE == "merge_request_event"'
- if: '$CI_COMMIT_BRANCH'
Astuce : Les quatres jobs s’exécutent en parallèle dans le même stage
quality, ce qui réduit le temps de pipeline. L’utilisation du cache Composer évite de re-télécharger les dépendances à chaque run.Par où commencer sur un projet existant ?
L’erreur classique est de vouloir tout activer d’un coup sur un projet legacy. Voici une approche pragmatique :
-
Style et formatage → Intégrez PHP CS Fixer avec les règles
@Symfony. Appliquez-le une fois sur toute la base de code, commitez, et activez-le en CI. -
Analyse statique niveau 0 → Ajoutez Rector en dry-run et mettez en place les nouvelles règles au niveau 0. → Ajoutez PHPStan niveau 0, générez une baseline. Zéro nouvelles erreurs autorisées dès maintenant.
-
Montée en niveau → Montez PHPStan niveau par niveau en corrigeant les erreurs de la baseline au fur et à mesure. Sur un projet existant le niveau 10 peut être trop exigeant, le niveau 6 est généralement suffisant. → Montez progressivement les niveaux des règles de Rector. Dès quelles sont atteintes, vous pourrez introduire de nouvelles règles.
-
Peaufiner le projet → Ajoutez Swiss-knife pour ajouter les dernières amélioration possibles.
Conclusion
L’analyse statique n’est pas un luxe réservé aux grands projets : c’est une pratique que l’on peut facilement intégrer dès le premier commit qui vous fera gagner du temps et de la sérénité. PHPStan pour détecter, Rector pour transformer et résorber la dette, PHP CS Fixer pour uniformiser : ensemble, ces outils constituent un filet de qualité solide autour de votre code PHP.