/rector

Instant Upgrades and Instant Refactoring of any PHP 5.3+ code

Primary LanguagePHPMIT LicenseMIT

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% of the task for you?

Coverage Status Downloads SonarCube



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 donations are welcome through PayPal.

Thank you:


Open-Source First

Rector instantly upgrades and instantly refactors the PHP code of your application.

It supports all versions of PHP from 5.2 and many open-source projects:



Drupal Rector rules


What Can Rector Do for You?

How to Apply Coding Standards?

Rector uses nikic/php-parser, that build on technology called abstract syntax tree) technology* (AST). AST doesn't care about spaces and produces mall-formatted code. That's why your project needs to have coding standard tool and set of rules, so it can make refactored nice and shiny again.

Don't have any coding standard tool? Add EasyCodingStandard and use prepared ecs-after-rector.php set.

Install

composer require rector/rector --dev
  • Having conflicts during composer require? → Use the Rector Prefixed
  • Using a different PHP version than Rector supports? → Use the Docker image

Running Rector

A. Prepared Sets

Featured open-source projects have prepared sets. You can find them in /config/set or by autocomplete of Rector\Set\ValueObject\SetList constants in rector.php config.

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

vendor/bin/rector process src --set symfony40 --dry-run

Rector will show you diff of files that it would change. To make the changes, drop --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. The best practice is to use config over command line:

<?php
// rector.php

declare(strict_types=1);

use Rector\Core\Configuration\Option;
use Rector\Set\ValueObject\SetList;
use Symfony\Component\DependencyInjection\Loader\Configurator\ContainerConfigurator;

return static function (ContainerConfigurator $containerConfigurator): void {
    $parameters = $containerConfigurator->parameters();

    $parameters->set(Option::SETS, [SetList::CODE_QUALITY]);
};

PHP config format is a new Symfony best practice.

B. Standalone Rules

In the end, it's best to combine few of basic sets and drop particular rules that you want to try:

<?php
// rector.php

declare(strict_types=1);

use Rector\Core\Configuration\Option;
use Rector\Set\ValueObject\SetList;
use Symfony\Component\DependencyInjection\Loader\Configurator\ContainerConfigurator;
use Rector\Php74\Rector\Property\TypedPropertyRector;

return static function (ContainerConfigurator $containerConfigurator): void {
    $parameters = $containerConfigurator->parameters();

    $services = $containerConfigurator->services();
    $services->set(TypedPropertyRector::class);

    $parameters->set(Option::SETS, [SetList::CODE_QUALITY]);
};

Then let Rector refactor your code:

vendor/bin/rector process src

👍


Note: rector.php is loaded by default. For different location, use --config option.

Features

Paths

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

<?php
// rector.php

declare(strict_types=1);

use Rector\Core\Configuration\Option;
use Symfony\Component\DependencyInjection\Loader\Configurator\ContainerConfigurator;

return static function (ContainerConfigurator $containerConfigurator): void {
    $parameters = $containerConfigurator->parameters();

    $parameters->set(Option::PATHS, [
        __DIR__ . '/src',
        __DIR__ . '/tests',
    ]);
};

Extra Autoloading

Rector relies on whatever autoload setup the project it is fixing is using by using the Composer autoloader as default. 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.php configuration file:

<?php
// rector.php

declare(strict_types=1);

use Rector\Core\Configuration\Option;
use Symfony\Component\DependencyInjection\Loader\Configurator\ContainerConfigurator;

return static function (ContainerConfigurator $containerConfigurator): void {
    $parameters = $containerConfigurator->parameters();

    $parameters->set(Option::AUTOLOAD_PATHS, [
        __DIR__ . '/vendor/squizlabs/php_codesniffer/autoload.php',
        __DIR__ . '/vendor/project-without-composer',
    ]);
};

Exclude Paths and Rectors

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

<?php
// rector.php

declare(strict_types=1);

use Rector\Core\Configuration\Option;
use Symfony\Component\DependencyInjection\Loader\Configurator\ContainerConfigurator;

return static function (ContainerConfigurator $containerConfigurator): void {
    $parameters = $containerConfigurator->parameters();

    $parameters->set(Option::EXCLUDE_PATHS, [
        __DIR__ . '/src/*/Tests/*',
    ]);
};

You can use a whole set, except 1 rule:

<?php
// rector.php

declare(strict_types=1);

use Rector\CodeQuality\Rector\If_\SimplifyIfReturnBoolRector;
use Rector\Core\Configuration\Option;
use Rector\Set\ValueObject\SetList;
use Symfony\Component\DependencyInjection\Loader\Configurator\ContainerConfigurator;

return static function (ContainerConfigurator $containerConfigurator): void {
    $parameters = $containerConfigurator->parameters();

    $parameters->set(Option::SETS, [
        SetList::CODE_QUALITY,
    ]);

    $parameters->set(Option::EXCLUDE_RECTORS, [
        SimplifyIfReturnBoolRector::class,
    ]);
};

For in-file exclusion, 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);
    }
}

Run Just 1 Rector Rule

Do you have config that includes many sets and Rectors? You might want to run only a single Rector. The --only argument allows that, e.g.:

vendor/bin/rector process src --set solid --only Rector\SOLID\Rector\Class_\FinalizeClassesWithoutChildrenRector

Or just short name:

vendor/bin/rector process src --set solid --only FinalizeClassesWithoutChildrenRector

Both will run only Rector\SOLID\Rector\Class_\FinalizeClassesWithoutChildrenRector.

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:

<?php
// rector.php

declare(strict_types=1);

use Rector\Core\Configuration\Option;
use Symfony\Component\DependencyInjection\Loader\Configurator\ContainerConfigurator;

return static function (ContainerConfigurator $containerConfigurator): void {
    $parameters = $containerConfigurator->parameters();

    $parameters->set(Option::PHP_VERSION_FEATURES, '7.2'); # your version is 7.3
};

Safe Types

In default setting:

<?php
// rector.php

declare(strict_types=1);

use Rector\Core\Configuration\Option;
use Symfony\Component\DependencyInjection\Loader\Configurator\ContainerConfigurator;

return static function (ContainerConfigurator $containerConfigurator): void {
    $parameters = $containerConfigurator->parameters();

    $parameters->set(Option::SAFE_TYPES, false);
};

All docblocks are taken seriously, e.g. with typed properties rule:

 <?php

 class ValueObject
 {
-    public $value;
+    public string $value;

    /**
     * @param string $value
     */
    public function __construct($value)
    {
        $this->value = $value;
    }
}

Do you want to use only explicit PHP type declaration? Enable safe_types:

<?php
// rector.php

declare(strict_types=1);

use Rector\Core\Configuration\Option;
use Symfony\Component\DependencyInjection\Loader\Configurator\ContainerConfigurator;

return static function (ContainerConfigurator $containerConfigurator): void {
    $parameters = $containerConfigurator->parameters();

    $parameters->set(Option::SAFE_TYPES, true);
};

Then, docblocks are skipped:

 <?php

 class ValueObject
 {
     public $value;

-    public $count;
+    public int $count;

    /**
     * @param string $value
     */
    public function __construct($value, int $count)
    {
        $this->value = $value;
        $this->count = $count
    }
}

Import Use Statements

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

<?php
// rector.php

declare(strict_types=1);

use Rector\Core\Configuration\Option;
use Symfony\Component\DependencyInjection\Loader\Configurator\ContainerConfigurator;

return static function (ContainerConfigurator $containerConfigurator): void {
    $parameters = $containerConfigurator->parameters();

    $parameters->set(Option::AUTO_IMPORT_NAMES, true);
};

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

<?php
// rector.php

declare(strict_types=1);

use Rector\Core\Configuration\Option;
use Symfony\Component\DependencyInjection\Loader\Configurator\ContainerConfigurator;

return static function (ContainerConfigurator $containerConfigurator): void {
    $parameters = $containerConfigurator->parameters();

    // this will not import root namespace classes, like \DateTime or \Exception
    $parameters->set(Option::IMPORT_SHORT_CLASSES, false);
    // this will not import classes used in PHP DocBlocks, like in /** @var \Some\Class */
    $parameters->set(Option::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

<?php
// rector.php

declare(strict_types=1);

use Rector\Core\Configuration\Option;
use Symfony\Component\DependencyInjection\Loader\Configurator\ContainerConfigurator;

return static function (ContainerConfigurator $containerConfigurator): void {
    $parameters = $containerConfigurator->parameters();

    $parameters->set(Option::SYMFONY_CONTAINER_XML_PATH_PARAMETER, __DIR__ .  '/var/cache/dev/AppKernelDevDebugContainer.xml');
};

More Detailed Documentation


How to Contribute

See the contribution guide.


Run Rector in Docker

You can run Rector on your project using Docker:

docker run --rm -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.php:

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

Debugging

  1. Make sure XDebug is installed and configured
  2. Add --xdebug option when running Rector

Without XDebug, you can use --debug option, that will print nested exceptions output.


Community Packages

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