Imagine that you are instructing an apprentice or junior programmer to go through your entire codebase, upgrade it to the latest version of PHP, and refactor the code to follow some pretty well laid out standards.
Now, imagine something even better: this programmer is instead a tool in your application that could do the same thing: conform your application code to meet your standards, upgrade it to support newer versions of PHP, and even identify and fix other potential issues that you may not even be aware of. Sounds pretty magical, right?
Well, that tool exists, and it's called Rector. Rector is a powerful tool that helps developers maintain consistency and improve the quality of their codebase. It does this by automatically refactoring code based on predefined rules. Developers can ensure that their code adheres to a specific set of coding standards and conventions, which makes it easier to understand, maintain, and evolve over time.
Rector can also help upgrade your codebase to a new framework, language, or library version. It can handle the most time-consuming and error-prone tasks and simplify the upgrade process.
Overall, Rector is a valuable tool for any developer looking to improve the quality and consistency of their codebase. With its ability to analyze code statically and make changes without breaking anything, Rector can help developers save time and effort while improving the overall quality of their code.
Let's dive in.
You can add Rector to your project using Composer:
composer require rector/rector --dev
There's also a community-created Rector extension for Laravel, which I maintain:
composer require driftingly/rector-laravel --dev
Once you've installed Rector, you'll want to create a configuration file:
vendor/bin/rector init
The init
command creates a file called rector.php
in your project's root directory. This file is where we'll add and configure the rules that we want Rector to follow. A rule is a PHP class used to find and transform code.
Let's start with a simple single-rule configuration for a Laravel application. Laravel 9 introduced a new to_route
helper. We can tell Rector we want to use to_route
instead of redirect()->route()
or Redirect::route()
using RedirectRouteToToRouteHelperRector
.
Replace the contents of your rector.php
file with:
<?php declare(strict_types=1); use Rector\Config\RectorConfig;use RectorLaravel\Rector\MethodCall\RedirectRouteToToRouteHelperRector; return static function (RectorConfig $rectorConfig): void { $rectorConfig->paths([ __DIR__ . '/app', __DIR__ . '/config', __DIR__ . '/database', __DIR__ . '/public', __DIR__ . '/resources', __DIR__ . '/routes', __DIR__ . '/tests', ]); $rectorConfig->rule(RedirectRouteToToRouteHelperRector::class);};
Now that we've told Rector what to look for, we can run it on our codebase:
# Preview changesvendor/bin/rector --dry-run # Runvendor/bin/rector
If your codebase uses either redirect()->route()
or Redirect::route()
you will see changes like this:
- return redirect()->route('home')->with('error', 'Incorrect Details.')+ return to_route('home')->with('error', 'Incorrect Details.')- return Redirect::route('home')->with('error', 'Incorrect Details.')+ return to_route('home')->with('error', 'Incorrect Details.')
Let's add some more rules to our rector.php
config file to see what else Rector can do.
Sets bundle rules together and can be added using $rectorConfig->sets()
. If we wanted to upgrade our code to be compatible with PHP 8.1 we would use the following:
$rectorConfig->sets([ LevelSetList::UP_TO_PHP_81,]);
Two other common sets are SetList::DEAD_CODE
(which removes code that doesn't have any effect) and SetList::CODE_QUALITY
(which fixes some common code quality issues). After adding these, our rector.php
file now looks like this:
<?php declare(strict_types=1); use Rector\Config\RectorConfig;use RectorLaravel\Rector\MethodCall\RedirectRouteToToRouteHelperRector;use Rector\Set\ValueObject\LevelSetList;use Rector\Set\ValueObject\SetList; return static function (RectorConfig $rectorConfig): void { $rectorConfig->paths([ __DIR__ . '/app', __DIR__ . '/config', __DIR__ . '/database', __DIR__ . '/public', __DIR__ . '/resources', __DIR__ . '/routes', __DIR__ . '/tests', ]); $rectorConfig->sets([ SetList::DEAD_CODE, SetList::CODE_QUALITY, LevelSetList::UP_TO_PHP_81, ]); $rectorConfig->rule(RedirectRouteToToRouteHelperRector::class);};
By adding only a few lines to our rector.php
file, we've improved code consistency an incredible amount. These three sets include over 150 individual rules. If you don't like a particular rule or need a rule skipped for a specific file or directory, you can update your config with a call to $rectorConfig->skip()
:
$rectorConfig->skip([ RecastingRemovalRector::class,]);
To view all the rules and sets, you can check out the Rector Documentation. Rector even includes a bunch of Laravel-specific rules.
So far, we've run Rector manually from the command line, but we can set it and forget it by adding it to our CI pipeline. My preferred way is through GitHub Actions.
Create a file in ./github/workflows
called rector.yaml
with the following:
# Inspiration https://github.com/symplify/symplify/blob/main/.github/workflows/rector.yamlname: Rector on: pull_request: null jobs: rector: runs-on: ubuntu-latest steps: - uses: actions/checkout@v2 with: token: "${{ secrets.ACCESS_TOKEN || secrets.GITHUB_TOKEN }}" - uses: shivammathur/setup-php@v2 with: php-version: 8.1 - uses: "ramsey/composer-install@v2" - run: vendor/bin/rector --ansi - uses: EndBug/add-and-commit@v5.1.0 with: add: . message: "[ci-review] Rector Rectify" author_name: "GitHub Action" author_email: "action@github.com" env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
When a pull request is created or updated, this action will run and commit any changes.
This automation is especially useful when a new developer joins the project. Their pull requests will be updated automatically before the first code review.
Another common way to automate these tasks is with a Husky pre-commit hook.
Hopefully, I've demonstrated how Rector can help maintain consistency in your projects.
Here are a few other ways you might use Rector.
For more information check out:
We appreciate your interest.
We will get right back to you.