Rector: Part 1 - What and How

4 min

Mon, Feb 19, 2018

X comments

Edit Post

Rector is a PHP tool that handles 2 things: instant upgrades and architecture refactorings.



What exactly Rector does and how does it work?

Read also:





What is Rector?

Rector is a PHP CLI tool build on Symfony Components that changes your PHP code for better. It only does what you tell it to do. You can use it to instantly upgrade your application or to do architecture refactorings once for the whole codebase.

Rector won't do your job. It's here to do the boring stuff for you. Its help is similar to coding standard tools' help with code reviews - move focus from spaces and commas to architecture of the code.

Where is it?

You can find it on Github. It has now 6 contributors in total. I want to thank young talented PHP developer Gabriel Caruso from Brazil for his great contributions since December 2017 that pushed Rector to a brand new level.

What are Instant Upgrades?

I'll show examples on Symfony, because that's the framework I know and love the best.

Let's say you have a project on Symfony 2.7. And you have a huge service.yml . You know that Symfony 2.8/3.0 brought an awesome autowiring feature that evolved to pure awesomenes in Symfony 3.3 and PSR-4 services feature.

Would you like to do this upgrade work manually? No. You can use Rector instead. Just run it with target level of symfony33 and it will change everything it knows about.

Such a command looks like this:

vendor/bin/rector process src --set symfony33

What are Architecture Refactorings?

The great task Rector can handle is to architecture refactorings. Your code might use a framework, but that's just 50 % of the code. The other 50 % is up to you, how you decide to use it - I mean static calls, services locators, facades over dependency injections etc.

I've seen many applications built on Symfony that used very interesting patterns:

class LoggingEventSubscriber implements EventSubscriberInterface { public function setController($controller) { $this->controller = $controller; } public function process() { $logger = $this->controller->get('logger'); $logger->log('it happened!'); } }

Let's say you'd like to remove all $this->get('logger') and replace them with dependency injection of LoggerInterface type. It's not strictly coupled to the Symfony (both Nette and Laravel allows this in some version) but you want to change this in the whole application.

From this:

class LectureController extends BaseController { public function listAction() { $logger = $this->get('logger'); $logger->log('it happened!'); } }

To this:

class LectureController extends BaseController { /** * @var LoggerInterface */ private $logger; public function __construct(LoggerInterface $logger) { $this->logger = $logger; } public function listAction() { $this->logger->log('it happened!'); } }

Rector can handle it for you.

Do you use Laravel and want to move from facades to constructor injection? Rector can help you.

How does it Work?

Rector parses the code to AST thanks to PHP superman nikic's php-parser.

Then it finds specific places in the code, e.g. all variables that contain Symfony\Component\HttpFoundation\Request type and call isMethodSafe() method.

Then it changes it into isMethodCacheable() (see UPGRADE-4.0.md).

Such a configuration looks like this (as shown in README ):

<?php // rector.php declare(strict_types=1); use Rector\Renaming\Rector\MethodCall\RenameMethodRector;use Rector\Set\ValueObject\SetList; use Symfony\Component\DependencyInjection\Loader\Configurator\ContainerConfigurator; return static function (ContainerConfigurator $containerConfigurator): void { $services = $containerConfigurator->services(); $services->set(RenameMethodRector::class) ->call('configure', [[ RenameMethodRector::OLD_TO_NEW_METHODS_BY_CLASS => [ 'Symfony\Component\HttpFoundation\Request' => [ 'isMethodSafe' => 'isMethodCacheable' ] ] ]]); };

Member of Big AST PHP Family

Rector is not the only tool that uses nikic\php-parser for context-aware operation on your code.

You've probably heard of PHPStan. But unfortunately it's read-only for deterministic cases = when 1 error has exactly 1 possible solution.

Another static analysis tool - vimeo/psalm by Matthew Brown, which fixes such code. Great job Matthew!

Easter Egg: Has Google Own "Rector"?

This setup and forget approach is so addictive, that Google must have it too, right?

And it does! I found 4-page case study Large-Scale Automated Refactoring Using ClangMR, that was presented by Hyrum Wright on CppCon2014 in 57 minutes. Hyrum doesn't work at Google anymore (as he wrote me), yet I still love his detailed and practical talk.

I'm still amazed by how their approach is 90% similar to Rector, just for C++.





Happy coding!