PHPStan 2.3.1, publié le 8 octobre 2026, analyse les incohérences de types et les appels impossibles ; Rector 2.7.0, publié le 6 octobre 2026, transforme automatiquement le code selon des règles explicites. Sur une application PHP ou Symfony legacy, leur association permet d’abord de rendre les défauts visibles, puis de moderniser des portions ciblées sans confondre automatisation et mise en production aveugle.
Le bon ordre n’est pas négociable : établir un état de l’analyse, corriger les contrats les plus ambigus, appliquer Rector en petits lots, puis tester le résultat dans les conditions du projet. Cette discipline évite qu’une modernisation syntaxique masque un problème métier ou une dépendance implicite du code historique.
PHPStan analyse, Rector transforme : deux responsabilités distinctes
PHPStan et Rector travaillent sur le code source, mais ils ne répondent pas à la même question. PHPStan cherche ce qui est incohérent dans les chemins de code qu’il peut raisonner : mauvais type transmis à une méthode, retour incompatible, propriété utilisée de manière incertaine ou appel sur une valeur potentiellement nulle. Il ne réécrit pas le dépôt : son résultat est un rapport à interpréter et à corriger.
Rector parcourt la structure syntaxique du code afin d’appliquer des transformations. Les règles peuvent remplacer des constructions anciennes, préparer une cible PHP ou accompagner une migration Symfony. Son rôle est donc mécanique, mais son résultat reste du code applicatif : il doit être revu, testé et livré avec la même exigence qu’une modification écrite à la main.
| Critère | PHPStan | Rector |
|---|---|---|
| Rôle principal | Détecter des incohérences statiques | Réécrire le code selon des règles |
| Production | Rapport d’erreurs et d’alertes | Différence de code à relire |
| Moment d’exécution | Avant chaque fusion et lors des montées de niveau | En préparation de lots de modernisation ou en vérification |
| Risque à maîtriser | Ignorer une alerte pertinente | Appliquer une transformation sans valider le comportement |
Rector complète une méthode de refactoring de projets PHP legacy, mais ne la remplace pas. Cette méthode doit conserver une cartographie des zones sensibles, des tests de non-régression et des décisions métier. Un outil peut modifier une syntaxe ; il ne peut pas décider qu’un ancien comportement fonctionnel doit disparaître.
Une séquence de travail fiable consiste à identifier une zone, formaliser son comportement par des tests lorsque c’est nécessaire, faire analyser cette zone par PHPStan, puis demander à Rector une proposition de changement. La revue porte alors sur une différence limitée et compréhensible, plutôt que sur un mélange de corrections de types, de migration framework et de nettoyage esthétique.
Installer et configurer PHPStan sur un périmètre utile
L’installation doit rester une dépendance de développement du projet. Commencer par analyser src et tests donne un périmètre cohérent : le code de production et les scénarios qui en décrivent l’usage progressent ensemble. Une configuration de niveau 8 convient à un dépôt qui a déjà absorbé une première phase de nettoyage ; elle peut être abaissée au départ si le volume d’erreurs empêche toute lecture utile.
composer require --dev phpstan/phpstan:^2.3
composer require --dev phpstan/phpstan-symfony
vendor/bin/phpstan analyse
Le fichier phpstan.neon doit être placé à la racine et évoluer avec le projet. Évitez les exclusions générales ajoutées sous pression : chaque exception durable réduit la valeur du rapport et doit être justifiée dans une revue.
parameters:
level: 8
paths:
- src
- tests
La configuration est volontairement courte. Elle constitue une base, pas un inventaire de tous les défauts historiques. Les options supplémentaires doivent répondre à un besoin observé : un répertoire généré, un bootstrap propre au projet ou une extension d’écosystème. La documentation officielle de PHPStan reste la référence pour vérifier la syntaxe et le comportement des paramètres selon la version utilisée.
Lancer l’analyse depuis la racine garantit que les chemins et les fichiers de configuration sont résolus de façon identique sur les postes locaux et dans la CI. Dans un dépôt Symfony, il est aussi préférable de ne pas assimiler le cache applicatif au code analysable : ce qui est généré doit être régénéré, non corrigé manuellement pour faire taire un analyseur.
Monter les niveaux sans submerger l'équipe
PHPStan propose les niveaux 0 à 10. Le niveau 0 cible les erreurs évidentes ; les niveaux suivants approfondissent progressivement la vérification des types, des retours et des appels, jusqu’au niveau 10, le plus strict. Une application ancienne qui passe directement à ce niveau maximal produit souvent un bruit tel que l’équipe perd le lien entre chaque signal et le risque réel.
Une progression réaliste démarre aux niveaux 5 ou 6. L’objectif initial est d’éliminer les erreurs qui révèlent des contrats manifestement faux, notamment les retours incohérents, les variables utilisées sans garantie suffisante et les appels dont les arguments ne correspondent pas à la signature attendue. Une fois le rapport stabilisé, viser le niveau 8 ou davantage devient un objectif de qualité vérifiable.
- Montez d’un niveau lorsque les erreurs du niveau précédent sont traitées ou explicitement isolées.
- Regroupez les corrections par domaine technique plutôt que par simple ordre d’apparition dans le rapport.
- Ajoutez ou renforcez les types PHP et les PHPDoc lorsque le code exprime réellement un contrat stable.
- Faites corriger les signaux dans les mêmes demandes de fusion que les changements fonctionnels concernés.
- Réévaluez les suppressions temporaires à chaque amélioration de niveau.
Le dépôt rector-symfony configure lui-même PHPStan au niveau 8 dans son fichier phpstan.neon, visible sur GitHub. Ce choix n’est pas une obligation universelle, mais pour un écosystème qui manipule des règles de transformation et des contrats Symfony complexes, ce palier documenté offre un repère concret. Sur un legacy, la question utile est : « quelles garanties pouvons-nous maintenir à chaque fusion ? », non « quel niveau affichons-nous le plus vite ? ».
Une baseline peut absorber les dettes héritées lors de l’introduction de PHPStan. Elle fige les erreurs existantes pour permettre à la CI d’interdire les nouvelles. Elle ne doit toutefois pas devenir un cimetière permanent : traitez-la comme un stock identifié, à réduire par lots, et non comme un fichier que personne ne consulte.
Analyser le conteneur Symfony avec phpstan-symfony
Le conteneur de services est une source classique d’imprécision dans les applications Symfony historiques. Sans extension dédiée, un appel à ContainerInterface::get() laisse facilement l’analyseur avec un type générique, alors que le code attend un service très précis. Cette incertitude favorise les erreurs cachées : identifiant de service invalide, mauvaise classe récupérée ou méthode appelée sur une abstraction trop vague.
L’extension phpstan/phpstan-symfony fournit les types de retour corrects pour ContainerInterface::get() et has(). Elle détecte aussi les services inexistants ainsi que les types incorrects récupérés depuis le conteneur. Lorsqu’il est présent, phpstan/extension-installer enregistre automatiquement l’extension ; à défaut, incluez explicitement vendor/phpstan/phpstan-symfony/extension.neon dans votre configuration.
includes:
- vendor/phpstan/phpstan-symfony/extension.neon
parameters:
level: 8
paths:
- src
- tests
Cette analyse éclaire les zones où l’application dépend encore du conteneur comme d’un registre universel. Elle ne force pas à refondre tous les services immédiatement, mais elle rend visibles les récupérations ambiguës et les usages qui ne correspondent plus à la définition réelle des services. C’est un bon point d’entrée pour remplacer progressivement les accès génériques par des dépendances injectées.
Les résultats doivent aussi nourrir une démarche plus large : auditer un parc applicatif et son plan de montée de version permet de relier les défauts détectés aux contraintes de versions PHP, aux bibliothèques maintenues et aux applications encore exposées à une échéance de support. Un rapport statique devient alors un élément de décision, pas seulement une liste de corrections.
Moderniser vers PHP 8.x avec Rector
Rector 2.7.0 déclare dans son dépôt source rector-src les dépendances phpstan/phpstan en version 2.3 et nikic/php-parser en version 5.9 : l’analyse et la transformation partagent donc la même fondation technique. Il peut appliquer des ensembles de règles orientés vers une version PHP cible grâce aux sets LevelSetList::UP_TO_PHP_80, UP_TO_PHP_81, UP_TO_PHP_82, UP_TO_PHP_83 et UP_TO_PHP_84. Le set choisi doit correspondre à la version réellement visée par l’application, ses dépendances et son environnement de déploiement.
<?php
use Rector\Config\RectorConfig;
use Rector\Set\ValueObject\LevelSetList;
return RectorConfig::configure()
->withPaths([
__DIR__ . '/src',
__DIR__ . '/tests',
])
->withSets([
LevelSetList::UP_TO_PHP_84,
]);
Avant toute écriture, exécutez systématiquement Rector avec --dry-run. Cette commande affiche les changements proposés sans toucher aux fichiers ; elle transforme l’outil en support de revue. La différence obtenue doit être découpée par thème : modernisation PHP, correction induite par un type, puis éventuel ajustement de test. Mélanger ces sujets dans une même demande de fusion complique l’identification d’une régression.
composer require --dev rector/rector rector/rector-symfony
vendor/bin/rector process --dry-run
Les échéances de PHP donnent une direction à cette configuration. Le calendrier de fin de vie de l’écosystème PHP, détaillé par endoflife.date et cohérent avec le tableau officiel des versions supportées de php.net, est sans ambiguïté : le support de la branche 8.1 s’est terminé le 31 décembre 2025 et PHP 8.2 ne recevra plus de correctifs de sécurité après le 31 décembre 2026. Les branches 8.3 et 8.4 restent, elles, maintenues en sécurité jusqu’au 31 décembre 2027 et au 31 décembre 2028 respectivement. Une cible PHP n’est donc pas une préférence syntaxique : elle doit résulter d’un plan de compatibilité et d’un calendrier de maintenance.
Appliquer les migrations Symfony avec rector-symfony
L’extension rector/rector-symfony ajoute des sets adaptés aux migrations Symfony. Un exemple est SymfonySetList::SYMFONY_70, mais le nom exact des constantes doit être vérifié dans la version réellement installée. Cette vérification est nécessaire : copier une configuration trouvée dans un article ancien peut produire une constante absente ou sélectionner une migration qui ne correspond pas au projet.
<?php
use Rector\Config\RectorConfig;
use Rector\Symfony\Set\SymfonySetList;
return RectorConfig::configure()
->withPaths([
__DIR__ . '/src',
__DIR__ . '/tests',
])
->withSets([
SymfonySetList::SYMFONY_70,
]);
Le dépôt rector-symfony déclare phpstan/phpstan ^2.2 comme dépendance de développement, ce qui illustre le lien étroit entre transformations et analyse. Rector peut modifier une construction dépréciée, mais PHPStan aide à confirmer que les types et les appels restent cohérents après la transformation. Les tests applicatifs restent indispensables pour les comportements dépendants de la configuration, de la base de données ou des intégrations externes.
Symfony 7.4 est la LTS, avec des corrections de bugs jusqu’en novembre 2028 et de sécurité jusqu’en novembre 2029 ; Symfony 8.1 est la stable courante. Le choix entre ces cibles doit être explicite dans la feuille de route. Une application qui cherche d’abord à stabiliser ses contrats peut viser une étape intermédiaire plutôt que d’accumuler, dans une seule livraison, migration PHP, migration Symfony et changements fonctionnels.
Intégrer PHPStan et Rector dans la CI
Dans la CI, PHPStan doit protéger le niveau de qualité atteint : une nouvelle erreur ne doit pas entrer silencieusement. Rector peut être exécuté avec --dry-run afin de signaler qu’une transformation attendue n’a pas été appliquée. Cette approche évite que le pipeline modifie lui-même la branche tout en donnant aux développeurs une indication claire sur l’action à effectuer.
- Exécutez PHPStan sur
srcettestsavec la même configuration qu’en local. - Lancez Rector en mode
--dry-runpour détecter les écarts avec les règles retenues. - Faites suivre ces vérifications par les tests du projet.
- Conservez des jobs séparés pour distinguer erreur de typage, transformation proposée et régression fonctionnelle.
- Utilisez le cache de manière cohérente, sans accepter qu’il masque un changement de dépendance ou de configuration.
La CI ne remplace pas la revue : elle réduit la quantité d’erreurs répétitives que les relecteurs doivent détecter. Pour structurer les pipelines, les règles de fusion et la responsabilité collective autour des contrôles, consultez ces pratiques DevOps et d’intégration continue. Le principe applicable ici est simple : un contrôle automatisé doit être reproductible, lisible et associé à une action attendue.
Ne rendez pas la CI plus stricte que ce que l’équipe sait traiter. Une baseline peut servir de sas initial, mais les fichiers nouveaux ou modifiés doivent respecter le niveau courant. Au fil des lots de correction, réduisez la baseline et augmentez le niveau plutôt que de maintenir indéfiniment deux standards de qualité dans le même dépôt.
Gérer les limites, faux positifs et dettes héritées
PHPStan ne connaît pas toutes les intentions métier et Rector ne prouve pas qu’une réécriture conserve chaque effet de bord. Les codes dynamiques, les métadonnées, les appels indirects ou les conventions internes peuvent nécessiter une information supplémentaire. Une alerte n’est donc ni une condamnation automatique ni une nuisance à supprimer : c’est une hypothèse technique à vérifier dans le contexte du projet.
Les bonnes pratiques qui limitent le risque sont concrètes :
- lancez Rector avec
--dry-runavant chaque application réelle ; - appliquez les transformations par petits lots faciles à annuler ;
- relisez les différences et exécutez les tests adaptés au domaine modifié ;
- documentez les suppressions PHPStan réellement justifiées ;
- utilisez une baseline pour l’existant, puis réduisez-la de manière planifiée ;
- vérifiez les sets Rector et Symfony disponibles dans les dépendances installées.
Un faux positif récurrent signale souvent un contrat insuffisamment exprimé. Ajouter un type de retour, préciser un tableau avec un PHPDoc ou injecter une dépendance explicite apporte davantage de valeur qu’une suppression locale. À l’inverse, un type artificiel uniquement destiné à satisfaire l’analyseur peut rigidifier le code et dissimuler son vrai comportement : la correction doit refléter la réalité d’exécution.
Une fois la dette de typage réduite et les transformations contrôlées, une cible plus récente devient beaucoup plus accessible. Le guide de migration vers PHP 8.5 peut alors servir à préparer la suite sans faire de la montée de version un saut non maîtrisé. PHPStan fournit des garde-fous, Rector accélère les changements répétitifs, mais la production reste protégée par les tests, la revue et un déploiement progressif.
FAQ
Les réponses ci-dessous traitent les questions opérationnelles qui reviennent lors de l’introduction de PHPStan et Rector dans une équipe responsable d’un applicatif PHP ou Symfony ancien. Elles couvrent notamment l’interprétation des alertes, l’adoption collective, la compatibilité avec un environnement ancien, l’usage encadré de l’IA et la place de ces contrôles dans la CI.