Rector : le sergent-instructeur de votre code qui n'a pas le temps pour vos conneries
Découvrez Rector, l'outil qui transforme votre code PHP sans patience pour vos erreurs de débutant.
Il y a des gens qui aiment bien passer leur temps à corriger manuellement le même putain de problème de code dans 743 fichiers différents. Ils adorent ça. Ils se lèvent le matin, ils prennent leur café, et ils se disent : "Tiens, et si aujourd'hui je passais 9 heures à chercher toutes les occurrences de new Class()
pour les remplacer par new class()
?" Ces gens-là sont soit masochistes, soit ils n'ont pas encore découvert Rector.
C'est quoi au juste Rector ?
Rector, c'est un outil de refactoring automatique pour PHP. C'est comme si tu avais un développeur senior qui serait à la fois ton coach personnel et ton psychiatre de code. Il regarde ton code, il secoue la tête d'un air désapprobateur, puis il te dit : "T'inquiète, je m'en occupe" — et pouf, ton code est propre.
Plus sérieusement, Rector est un outil qui permet d'appliquer automatiquement des transformations sur ton code PHP. Il peut :
- Upgrader ton code vers des versions plus récentes de PHP
- Moderniser la façon dont tu écris ton code
- Appliquer les bonnes pratiques (et oui, même celles que tu fais semblant de connaître)
- Refactoriser ton code pour utiliser les fonctionnalités récentes de Symfony, Doctrine et autres
- Standardiser ton code pour qu'il suive les conventions
Et le plus beau dans tout ça ? Il fait tout ça sans se plaindre, sans te juger, et sans te demander une augmentation.
Pourquoi tu devrais l'utiliser
Moi je connais deux types de développeurs :
- Ceux qui utilisent Rector
- Ceux qui aiment passer leur week-end à faire des chercher/remplacer
Si tes dans la deuxième catégorie, tu as un problème.
Les avantages ?
- Gain de temps : ce que tu ferais en 4 heures, Rector le fait en 2 minutes. Pendant que toi, tu es encore en train de te demander si tu dois mettre un espace après la flèche dans ta fonction fléchée.
- Cohérence : Rector va appliquer les mêmes règles partout. Pas comme toi qui oublies de mettre des types de retour sur une fonction sur deux parce que tu étais fatigué.
- Apprentissage : Tu découvres des bonnes pratiques que tu connaissais même pas. C'est comme avoir un mentor, mais sans les conseils non sollicités sur ta vie personnelle.
- Confiance : Tu peux migrer de PHP 7.4 à PHP 8.4 sans passer par la case "Mon site est down parce que j'ai oublié de vérifier que
foo()
n'existe plus dans la nouvelle version".
Ma configuration Rector
Allez, je vais te montrer ma config Rector. C'est un peu comme montrer sa collection de timbres, mais pour les nerds :
<?php
declare(strict_types=1);
use App\Rector\RemovePhpAttributeImportsRector;
use Rector\Config\RectorConfig;
use Rector\Doctrine\Set\DoctrineSetList;
use Rector\Php80\Rector\Class_\ClassPropertyAssignToConstructorPromotionRector;
use Rector\Set\ValueObject\LevelSetList;
use Rector\Set\ValueObject\SetList;
use Rector\Symfony\Set\SymfonySetList;
use Rector\TypeDeclaration\Rector\Property\TypedPropertyFromStrictConstructorRector;
use Rector\ValueObject\PhpVersion;
try {
return RectorConfig::configure()
->withParallel(120, 16, 10)
->withPhpVersion(PhpVersion::PHP_84)
->withPhpSets(php84: true)
->withPaths([
__DIR__.'/src',
__DIR__.'/tests',
])
->withAttributesSets(
symfony: true,
doctrine: true,
gedmo: true,
)
->withSets([
SetList::EARLY_RETURN,
SetList::STRICT_BOOLEANS,
SetList::CODE_QUALITY,
SetList::CODING_STYLE,
SetList::DEAD_CODE,
SetList::PRIVATIZATION,
SetList::TYPE_DECLARATION,
LevelSetList::UP_TO_PHP_84,
LevelSetList::UP_TO_PHP_83,
LevelSetList::UP_TO_PHP_82,
LevelSetList::UP_TO_PHP_81,
LevelSetList::UP_TO_PHP_80,
DoctrineSetList::ANNOTATIONS_TO_ATTRIBUTES,
DoctrineSetList::DOCTRINE_CODE_QUALITY,
SymfonySetList::SYMFONY_72,
SymfonySetList::SYMFONY_CODE_QUALITY,
SymfonySetList::SYMFONY_CONSTRUCTOR_INJECTION,
])
->withRules([
TypedPropertyFromStrictConstructorRector::class,
RemovePhpAttributeImportsRector::class,
])
->withSkip([
ClassPropertyAssignToConstructorPromotionRector::class => __DIR__.'/src/Entity',
]);
} catch (Rector\Exception\Configuration\InvalidConfigurationException $e) {
// Gestion de l'erreur ou rapport silencieux
}
Alors, prenons cette configuration ligne par ligne :
Configuration de base
return RectorConfig::configure()
Ça, c'est pour dire "Hé Rector, écoute-moi bien, j'ai des instructions pour toi".
Les paramètres de performance
->withParallel(120, 16, 10)
C'est comme quand tu dis à tes 10 stagiaires : "Allez, vous avez tous la même tâche, celui qui la finit le premier a le droit de rentrer chez lui". Sauf que là, c'est plus comme 120 stagiaires, 16 par équipe, avec un timeout de 10 secondes. Ça va VITE, mon gars.
La version de PHP ciblée
->withPhpVersion(PhpVersion::PHP_84)
->withPhpSets(php84: true)
C'est pour dire à Rector : "Mec, mon code doit être prêt pour PHP 8.4, parce que je suis un putain de visionnaire et j'ai besoin de ce garbage collector optimisé pour gagner 0.002 millisecondes sur mon temps de chargement".
Les chemins à analyser
->withPaths([
__DIR__.'/src',
__DIR__.'/tests',
])
"Regarde Rector, je veux que tu t'occupes de mon code source et de mes tests, mais t'as pas besoin d'aller fourrer ton nez dans mes dépendances, ça va bien se passer".
Les ensembles d'attributs modernes
->withAttributesSets(
symfony: true,
doctrine: true,
gedmo: true,
)
Là, on dit à Rector de transformer les vieilles annotations (tu sais, ces lignes qui commencent par @
et qui ressemblent à des tweets de boomer) en attributs modernes de PHP 8 (ces trucs avec des crochets qui ressemblent à des décorations de Noël).
Les ensembles de règles
->withSets([
SetList::EARLY_RETURN, // Sortir tôt des fonctions, comme quand tu quittes une soirée nulle
SetList::STRICT_BOOLEANS, // Parce que peut-être c'est pas une réponse en informatique
SetList::CODE_QUALITY, // Pour que ton code soit plus beau que ta photo Tinder
SetList::CODING_STYLE, // Pour unifier ton style, genre pas un espace ici et trois là
SetList::DEAD_CODE, // Pour virer le code zombie qui sert à rien
SetList::PRIVATIZATION, // Pour cacher tes propriétés comme tes sentiments
SetList::TYPE_DECLARATION, // Pour mettre des types partout, parce que l'anarchie c'est fini
// Pour monter de version en version comme un upgrade de Pokémon
LevelSetList::UP_TO_PHP_84,
LevelSetList::UP_TO_PHP_83,
LevelSetList::UP_TO_PHP_82,
LevelSetList::UP_TO_PHP_81,
LevelSetList::UP_TO_PHP_80,
// Pour Doctrine, parce que les annotations c'est tellement 2019
DoctrineSetList::ANNOTATIONS_TO_ATTRIBUTES,
DoctrineSetList::DOCTRINE_CODE_QUALITY,
// Pour Symfony, parce que si tu utilises pas la dernière version, tu es ringard
SymfonySetList::SYMFONY_72,
SymfonySetList::SYMFONY_CODE_QUALITY,
SymfonySetList::SYMFONY_CONSTRUCTOR_INJECTION,
])
C'est comme un menu dégustation dans un resto étoilé, sauf que c'est pour ton code. Tu prends un peu de tout, et à la fin, ton code ressemble à quelque chose qu'un développeur senior aurait écrit, même si tu as commencé à coder il y a 3 semaines.
Les règles personnalisées
->withRules([
TypedPropertyFromStrictConstructorRector::class,
RemovePhpAttributeImportsRector::class,
])
Là, j'ajoute deux règles spécifiques :
- La première pour ajouter des types à mes propriétés automatiquement
- Et ma règle custom
RemovePhpAttributeImportsRector
qui supprime les imports inutiles d'attributs natifs PHP
Les exceptions
->withSkip([
ClassPropertyAssignToConstructorPromotionRector::class => __DIR__.'/src/Entity',
])
"Rector, tu es cool, mais s'il te plaît, ne transforme pas les propriétés de mes entités en paramètres de constructeur promoted, j'ai mes raisons". C'est comme dire à ton coiffeur "Tu coupes tout, sauf la mèche de devant".
Et la règle custom, on en parle ?
J'ai créé une règle custom dans mon projet. Parce que parfois, même les outils parfaits ont besoin d'être perfectionnés. C'est comme mettre un sticker sur ta Ferrari.
Ma règle RemovePhpAttributeImportsRector
, c'est pour virer les imports d'attributs PHP natifs qu'on n'a pas besoin d'importer. Par exemple, au lieu de :
use Override;
class Truc {
#[Override]
public function method() {}
}
On a directement (remarque le backslash qui indique le namespace global) :
class Truc {
#[\Override]
public function method() {}
}
Pourquoi ? Parce que c'est plus propre, plus explicite, et ça évite de surcharger ton espace de noms avec des trucs que PHP connaît déjà. C'est comme si tu te présentais à chaque fois en disant "Bonjour, je suis Humain Pierre" au lieu de juste "Bonjour, je suis Pierre".
La règle est plutôt simple :
class RemovePhpAttributeImportsRector extends AbstractRector
{
private const array PHP_ATTRIBUTES = [
'Override',
'Attribute',
'AttributeOverride',
'Deprecated',
'Pure',
'ReturnTypeWillChange',
'Template',
'Transient',
'TransientDeprecated',
];
// ... le reste du code ...
private function isPhpAttribute(UseUse $use): bool
{
$lastName = $use->name->getLast();
return in_array($lastName, self::PHP_ATTRIBUTES, true);
}
}
Comment utiliser Rector dans tes projets
1. Installation
D'abord, installes-le dans ton projet :
composer require --dev rector/rector
2. Configuration
Crée un fichier rector.php
à la racine de ton projet. Tu peux commencer par un truc simple comme :
<?php
declare(strict_types=1);
use Rector\Config\RectorConfig;
use Rector\Set\ValueObject\SetList;
return RectorConfig::configure()
->withPhpVersion(PhpVersion::PHP_82)
->withPaths([
__DIR__ . '/src',
])
->withSets([
SetList::CODE_QUALITY,
SetList::DEAD_CODE,
]);
3. Exécution
Pour voir ce que Rector va changer sans toucher à ton code :
vendor/bin/rector process --dry-run
Et quand tu es prêt à faire les changements pour de vrai :
vendor/bin/rector process
Dans mon projet, j'ai intégré Rector à mon Makefile pour pouvoir l'exécuter facilement :
qa-fix-php: ## Corriger le code PHP avec php-cs-fixer et rector dans Docker
@docker run -v $(PWD):/app -w /app -t --rm -e PHP_CS_FIXER_IGNORE_ENV=1 php:8.4-cli-alpine php -d memory_limit=-1 ./vendor/bin/php-cs-fixer fix src tests --config=.php-cs-fixer.dist.php --using-cache=no --verbose --diff
@docker run -v $(PWD):/app -w /app -t --rm php:8.4-cli-alpine php -d memory_limit=-1 ./vendor/bin/rector process --config=rector.php --clear-cache
Les ensembles de règles ("sets") les plus utiles
Rector a une tonne de sets prédéfinis. C'est comme si t'allais au McDrive et qu'au lieu de commander chaque truc individuellement, tu pouvais juste dire "Donne-moi le menu Maximum Refactoring avec la sauce clean code".
Quelques-uns des plus utiles :
- CODE_QUALITY : Améliore la qualité générale de ton code (c'est basique, mais ça fait le taf)
- EARLY_RETURN : Optimise tes fonctions pour qu'elles sortent tôt, parce que personne n'aime les niveaux d'indentation qui ressemblent à l'échelle de Richter
- PRIVATIZATION : Rend privé tout ce qui peut l'être, parce que ton code a besoin de vie privée aussi
- DEAD_CODE : Supprime le code mort, parce que ton projet c'est pas The Walking Dead
- TYPE_DECLARATION : Ajoute des types partout, parce qu'on est en 2025 bordel, pas en 2009
- CODING_STYLE : Standardise ton style, pour que ton code ressemble à quelque chose de professionnel et pas à un devoir de première année
Pour Symfony et Doctrine, il y a des sets spécifiques comme :
- SYMFONY_CODE_QUALITY : Pour un code Symfony aux petits oignons
- SYMFONY_CONSTRUCTOR_INJECTION : Pour injecter tes services comme un pro
- ANNOTATIONS_TO_ATTRIBUTES : Pour passer des vieilles annotations aux attributs modernes
Prévenir les erreurs
Si tu as peur que Rector ne casse ton code (ce qui n'arrivera jamais, jamais, jamais... bon, peut-être parfois), voici quelques conseils :
-
Toujours commiter avant : Si tu es pas le genre de personne qui commit toutes les 5 minutes, fais-le au moins avant de lancer Rector.
-
Utilise
--dry-run
d'abord : Ça te montre ce qui va changer sans rien changer. -
Lance tes tests après : Si tu as des tests, ce qui est le cas si tu es un développeur responsable (et si tu en n'as pas, on va faire semblant que je t'ai pas posé la question).
-
Exclue les parties sensibles : Utilise
withSkip()
pour les morceaux de code où tu préfères que Rector ne touche pas.
Les erreurs fréquentes (comme si tu n'allais pas en faire)
-
"J'ai lancé Rector sur vendor/" : Bravo, t'as essayé de refactoriser le code des autres. Maintenant, ton projet est cassé et tu ne sais pas pourquoi. Spécifie toujours les bons chemins.
-
"J'ai utilisé toutes les règles d'un coup" : Ah, l'optimisme. C'est comme vouloir perdre 20 kilos en une semaine. Commence doucement, règle par règle.
-
"J'ai mis à jour la version PHP sans vérifier la compatibilité" : Et maintenant ton site est down. Surprenant.
-
"J'ai pas lu la doc" : C'est comme monter un meuble IKEA sans les instructions, et après se plaindre qu'il reste des pièces.
Le mot de la fin
Rector, c'est comme avoir un senior developer qui bosse pour toi 24/7, sans jamais se plaindre, sans demander d'augmentation, et qui ne te juge pas quand tu écris du code de merde à 3h du matin.
Si tu l'utilises pas encore, c'est soit que u 'aimes souffrir, soit que tu es masochiste, soit les deux. Dans tous les cas, tu as besoin d'aide, et cette aide s'appelle Rector.
Ton code te remerciera, ton équipe te remerciera, et ton psy aussi parce que tu auras moins de crises d'angoisse à cause de ton code legacy.