rector/README.md

12 KiB

Rector - Upgrade Your Legacy App to a Modern Codebase

Rector is a reconstructor tool - it does instant upgrades and instant refactoring of your code. Why refactor manually if Rector can handle 80% for you?

Build Status with Travis CI Build Status Github Actions Coverage Status Downloads

Rector-showcase


Sponsors

Rector grows faster with your help, the more you help the more work it saves you. Check out Rector's Patreon. One-time donation is welcomed through PayPal.

Thank you:


Open-Source First

Rector instantly upgrades and instantly refactors the PHP code of your application. It supports all modern versions of PHP and many open-source projects:




What Can Rector Do for You?

...look at the overview of all available Rectors with before/after diffs and configuration examples. You can use them to build your own sets.

How to Apply Coding Standards?

The AST libraries that Rector uses aren't well-suited for coding standards, so it's better to let coding standard tools do that.

Don't have a coding standard tool for your project? Consider adding EasyCodingStandard, PHP CS Fixer or PHP_CodeSniffer.

Tip: If you have EasyCodingStandard, you can start your set with ecs-after-rector.yaml.

Install

composer require rector/rector --dev

Do you have conflicts during composer require or on run?

Do you need different PHP version than Rector supports?

Running Rector

A. Prepared Sets

Featured open-source projects have prepared sets. You can find them in /config/set or by running:

vendor/bin/rector sets

Let's say you pick the symfony40 set and you want to upgrade your /src directory:

# show a list of known changes in Symfony 4.0
vendor/bin/rector process src --set symfony40 --dry-run
# apply upgrades to your code
vendor/bin/rector process src --set symfony40

Some sets, such as code-quality can be used on a regular basis. You can include them in your rector.yaml to run them by default:

# rector.yaml
parameters:
    sets:
        - 'code-quality'
        - 'php71'
        - 'php72'
        - 'php73'

B. Custom Sets

  1. Create a rector.yaml config file with your desired Rectors:

    services:
        Rector\Rector\Architecture\DependencyInjection\AnnotatedPropertyInjectToConstructorInjectionRector:
            $annotation: "inject"
    
  2. Run Rector on your /src directory:

    vendor/bin/rector process src --dry-run
    # apply
    vendor/bin/rector process src
    

Features

Extra Autoloading

Rector relies on project and autoloading of its classes. To specify your own autoload file, use --autoload-file option:

vendor/bin/rector process ../project --autoload-file ../project/vendor/autoload.php

Or use a rector.yaml config file:

# rector.yaml
parameters:
    autoload_paths:
        - 'vendor/squizlabs/php_codesniffer/autoload.php'
        - 'vendor/project-without-composer'

Exclude Paths and Rectors

You can also exclude files or directories (with regex or fnmatch):

# rector.yaml
parameters:
    exclude_paths:
        - '*/src/*/Tests/*'

You can use a whole ruleset, except one rule:

# rector.yaml
parameters:
    exclude_rectors:
        - 'Rector\CodeQuality\Rector\If_\SimplifyIfReturnBoolRector'

Do you want to skip just specific line with specific rule?

Use @noRector \FQN name annotation:

class SomeClass
{
    /**
     * @noRector \Rector\DeadCode\Rector\ClassMethod\RemoveEmptyClassMethodRector
     */
    public function foo()
    {
        /** @noRector \Rector\DeadCode\Rector\Plus\RemoveDeadZeroAndOneOperationRector */
        round(1 + 0);
    }
}

Provide PHP Version

By default Rector uses the language features matching your system version of PHP. You can configure it for a different PHP version:

# rector.yaml
parameters:
    php_version_features: '7.2' # your version is 7.3

Paths

If you're annoyed by repeating paths in arguments, you can move them to config instead:

# rector.yaml
parameters:
    paths:
        - 'src'
        - 'tests'

Import Use Statements

FQN classes are not imported by default. If you don't to do do it manually after every Rector run, enable it by:

# rector.yaml
parameters:
    auto_import_names: true

You can also fine-tune how these imports are processed:

# rector.yaml
parameters:
    # this will not import root namespace classes, like \DateTime or \Exception
    import_short_classes: false

    # this will not import classes used in PHP DocBlocks, like in /** @var \Some\Class */
    import_doc_blocks: false

Limit Execution to Changed Files

Execution can be limited to changed files using the process option --match-git-diff. This option will filter the files included by the configuration, creating an intersection with the files listed in git diff.

vendor/bin/rector process src --match-git-diff

This option is useful in CI with pull-requests that only change few files.

Symfony Container

To work with some Symfony rules, you now need to link your container XML file

# rector.yaml
parameters:
    # path to load services from
    symfony_container_xml_path: 'var/cache/dev/AppKernelDevDebugContainer.xml'

3 Steps to Create Your Own Rector

First, make sure it's not covered by any existing Rectors.

Let's say we want to change method calls from set* to change*.

 $user = new User();
-$user->setPassword('123456');
+$user->changePassword('123456');

1. Create a New Rector and Implement Methods

Create a class that extends Rector\Rector\AbstractRector. It will inherit useful methods e.g. to check node type and name. See the source (or type $this-> in an IDE) for a list of available methods.

<?php

declare(strict_types=1);

namespace App\Rector;

use Nette\Utils\Strings;
use PhpParser\Node;
use PhpParser\Node\Identifier;
use PhpParser\Node\Expr\MethodCall;
use Rector\Rector\AbstractRector;
use Rector\RectorDefinition\CodeSample;
use Rector\RectorDefinition\RectorDefinition;

final class MyFirstRector extends AbstractRector
{
    public function getDefinition(): RectorDefinition
    {
        // what does this do?
        // minimalistic before/after sample - to explain in code
        return new RectorDefinition('Change method calls from set* to change*.', [
            new CodeSample('$user->setPassword("123456");', '$user->changePassword("123456");')
        ]);
    }

    /**
     * @return string[]
     */
    public function getNodeTypes(): array
    {
        // what node types we look for?
        // pick any node from https://github.com/rectorphp/rector/blob/master/docs/NodesOverview.md
        return [MethodCall::class];
    }

    /**
     * @param MethodCall $node - we can add "MethodCall" type here, because only this node is in "getNodeTypes()"
     */
    public function refactor(Node $node): ?Node
    {
        // we only care about "set*" method names
        if (! $this->isName($node, 'set*')) {
            // return null to skip it
            return null;
        }

        $methodCallName = $this->getName($node);
        $newMethodCallName = Strings::replace($methodCallName, '#^set#', 'change');

        $node->name = new Identifier($newMethodCallName);

        // return $node if you modified it
        return $node;
    }
}

2. Register It

# rector.yaml
services:
    App\Rector\MyFirstRector: ~

3. Let Rector Refactor Your Code

# see the diff first
vendor/bin/rector process src --dry-run

# if it's ok, apply
vendor/bin/rector process src

That's it!

More Detailed Documentation

How to Contribute

Just follow 3 rules:

  • 1 feature per pull-request

  • New features need tests

  • Tests, coding standards and PHPStan checks must pass:

    composer complete-check
    

    Do you need to fix coding standards? Run:

    composer fix-cs
    

We would be happy to accept PRs that follow these guidelines.

Run Rector in Docker

You can run Rector on your project using Docker:

docker run -v $(pwd):/project rector/rector:latest process /project/src --set symfony40 --dry-run

# Note that a volume is mounted from `pwd` (the current directory) into `/project` which can be accessed later.

Using rector.yaml:

docker run -v $(pwd):/project rector/rector:latest process /project/app --config /project/rector.yaml --autoload-file /project/vendor/autoload.php --dry-run

Community Packages

Do you use Rector to upgrade your code? Add it here: