Safely upgrade from PHP 7.4 to 8.1 using Rector

Safely upgrade from PHP 7.4 to 8.1 using Rector

You just have to try Rector. Heck, let the tests break, just run it.

ยท

4 min read

I have to say it from the start, the only thing that comes close to safely upgrading a codebase is having a solid set of automated tests. Nothing gives you more comfort than a bunch of green checkmarks dancing on the screen.

With that said, we're going to upgrade a Laravel project running on the soon-to-be-dead PHP 7.4 (Nov 28). Currently, the last stable PHP version is 8.1 and we're going to upgrade to it using a tool called Rector. Rector will help us move on to the new syntax in a very comfortable way.

Without further ado, here are the steps I followed.

Change composer.json to the new PHP 8.1

"require": {
    "php": "^8.1",
    ...
}

Alongside manually changing the version in composer.json, I also changed my environment to use PHP 8.1. In Homestead, that's done simply by running php81. In Valet that command is valet use php@8.1. If you're on Windows and using Wamp or Xampp, well, good luck ๐Ÿ˜.

Do a composer update

After changing the environment, I ran a nice and risky composer update. Not entirely sure about this, as there might be a cleaner way, but I guess composer needs to check and update all packages to the specified PHP version.

This is the point where you'll probably get stuck and face composer errors because not all packages you use support the new PHP.

Check for packages that might break

In this particular project, the only package that did not have support was fzaninotto/faker, and that's because that project has said goodnight since 2020. Good news though, there's an alternative to it called fakerphp/faker, which you can just use directly in composer.json ("fzaninotto/faker" => "fakerphp/faker"). And you don't need to change a thing in your factories, it just works.

Run the tests

At this point, I run the tests, and I notice nothing breaks, they're all passing. Phew. However, if it doesn't go as smoothly for you, or you don't have tests, check out the deprecations here. Just make sure that you've handled those and ignore the new syntax, because we're not going to upgrade to it the old fashion way. Just commit your changes so you have a clean slate for the syntax changes.

Install, configure, and run Rector

composer require rector/rector --dev
vendor/bin/rector init

This command will install Rector for you and create a rector.php file at the root of your project. You can modify it to tell Rector to upgrade all the codebase up to PHP 8.1, with this configuration:

return static function (RectorConfig $rectorConfig): void {
    $rectorConfig->paths([
        __DIR__ . '/app',
    ]);

    $rectorConfig->importNames();

    $rectorConfig->sets([
        LevelSetList::UP_TO_PHP_81,
    ]);

    $rectorConfig->skip([
        SpatieEnumClassToEnumRector::class,
    ]);
};

We'll discuss that last rule shortly, but now you should be able to run vendor/bin/rector --dry-run. If your codebase is huge, you'll have to wait a minute or two. When it's done you'll see all the changes that are to be applied, like a git diff. If you omit the --dry-run it will instead go ahead and do all those changes to your code, so you can pick what you want to keep in your diff browser of choice.

That last rule SpatieEnumClassToEnumRector is skipped because I'm using the spatie/enum package, and I don't want it to be converted to PHP native enums automatically. The reason for that is that the Spatie package has some nice little helpers, and it's safer in my opinion to migrate some of the enums manually.

Another little gotcha I want to point out is with the match expression. It does strict comparisons, unlike switch, and that might do some damage if left unchecked. As a remedy, you can use the match (true) {...} version, which is not as beautiful but will do a loose comparison like the switch.

I'm not going to go over what's new in 8.1 and what Rector will do for you, but damn it feels good to see all the code clean itself. PHPStorm supports it out of the box. You just have to try it, heck, let the tests break, just run it.

ย