rector/README.md

472 lines
14 KiB
Markdown
Raw Normal View History

# Rector - Upgrade Your Legacy App to a Modern Codebase
2017-07-15 19:20:20 +02:00
Rector is a **rec**onstruc**tor** tool - it does **instant upgrades** and **instant refactoring** of your code.
2020-03-21 11:41:11 +01:00
Why refactor manually if Rector can handle 80% of the task for you?
2018-02-02 17:51:41 +01:00
2018-11-09 14:45:14 +01:00
[![Coverage Status](https://img.shields.io/coveralls/rectorphp/rector/master.svg?style=flat-square)](https://coveralls.io/github/rectorphp/rector?branch=master)
2018-07-02 15:02:27 +02:00
[![Downloads](https://img.shields.io/packagist/dt/rector/rector.svg?style=flat-square)](https://packagist.org/packages/rector/rector)
[![SonarCube](https://img.shields.io/badge/SonarCube_Debt-%3C25-brightgreen.svg?style=flat-square)](https://sonarcloud.io/dashboard?id=rectorphp_rector)
2017-07-15 19:20:20 +02:00
2020-02-21 15:26:02 +01:00
<br>
2020-03-21 11:41:11 +01:00
- **[Overview of all 450+ Rectors](/docs/AllRectorsOverview.md)**
2020-04-14 21:52:27 +02:00
- **[Online DEMO](https://getrector.org/demo)**
2020-02-21 15:26:02 +01:00
<br>
2020-02-13 17:13:49 +01:00
![Rector-showcase](docs/images/rector-showcase-var.gif)
2018-01-13 16:01:31 +01:00
2019-04-29 23:42:11 +02:00
<br>
## Sponsors
Rector grows faster with your help, the more you help the more work it saves you.
2020-03-21 11:41:11 +01:00
Check out [Rector's Patreon](https://www.patreon.com/rectorphp). One-time donations are welcome [through PayPal](https://www.paypal.me/rectorphp).
2019-04-29 23:42:11 +02:00
2019-08-19 15:49:41 +02:00
Thank you:
2019-08-19 15:50:06 +02:00
<a href="https://spaceflow.io/en"><img src="/docs/images/spaceflow.png"></a>
2019-08-19 15:49:41 +02:00
2019-04-29 23:42:11 +02:00
<br>
## 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:
2017-07-15 19:20:20 +02:00
2018-10-21 11:00:39 +02:00
<br>
2017-10-30 16:00:28 +01:00
<p align="center">
2019-06-08 22:41:52 +02:00
<a href="/config/set/php"><img src="/docs/images/php.png"></a>
2019-10-20 16:46:52 +02:00
<img src="/docs/images/space.png" width=40>
2019-06-08 22:41:52 +02:00
<a href="/config/set/symfony"><img src="/docs/images/symfony.png"></a>
2019-10-20 16:46:52 +02:00
<img src="/docs/images/space.png" width=40>
2019-10-20 16:47:40 +02:00
<a href="/config/set/laravel"><img src="/docs/images/laravel.png"></a>
<br>
<a href="/config/set/cakephp"><img src="/docs/images/cakephp.png"></a>
<img src="/docs/images/space.png" width=40>
<a href="/config/set/phpunit"><img src="/docs/images/phpunit.png"></a>
2019-10-20 16:46:52 +02:00
<img src="/docs/images/space.png" width=40>
2019-06-08 22:41:52 +02:00
<a href="/config/set/twig"><img src="/docs/images/twig.png"></a>
2017-10-30 16:00:28 +01:00
</p>
2017-08-20 17:40:19 +02:00
2018-10-21 11:00:39 +02:00
<br>
## What Can Rector Do for You?
2018-08-01 22:29:01 +02:00
2019-04-29 23:42:11 +02:00
- Rename classes, methods, properties, namespaces or constants
2020-01-15 08:14:05 +05:30
- Complete [parameter, var or return type declarations](https://www.tomasvotruba.com/blog/2019/01/03/how-to-complete-type-declarations-without-docblocks-with-rector/) based on static analysis of your code
2019-04-29 23:42:11 +02:00
- Upgrade your code from PHP 5.3 to PHP 7.4
2020-01-14 22:20:38 +01:00
- [Migrate your project from Nette to Symfony](https://www.tomasvotruba.com/blog/2019/02/21/how-we-migrated-from-nette-to-symfony-in-3-weeks-part-1/)
- [Complete PHP 7.4 property type declarations](https://www.tomasvotruba.com/blog/2018/11/15/how-to-get-php-74-typed-properties-to-your-code-in-few-seconds/)
- [Refactor Laravel facades to dependency injection](https://www.tomasvotruba.com/blog/2019/03/04/how-to-turn-laravel-from-static-to-dependency-injection-in-one-day/)
- [Prepare a codebase before huge upgrades](https://www.tomasvotruba.com/blog/2019/12/16/8-steps-you-can-make-before-huge-upgrade-to-make-it-faster-cheaper-and-more-stable/)
- [Get rid of technical debt](https://www.tomasvotruba.com/blog/2019/12/09/how-to-get-rid-of-technical-debt-or-what-we-would-have-done-differently-2-years-ago/)
2017-12-28 17:58:35 -02:00
- And much more...
2017-07-15 19:20:20 +02:00
...**look at the overview of [all available Rectors](/docs/AllRectorsOverview.md)** with before/after diffs and configuration examples. You can use them to build your own sets.
2018-04-29 11:03:47 +02:00
## 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](https://github.com/Symplify/EasyCodingStandard), [PHP CS Fixer](https://github.com/FriendsOfPHP/PHP-CS-Fixer) or [PHP_CodeSniffer](https://github.com/squizlabs/PHP_CodeSniffer).
2019-11-08 18:02:29 +01:00
Tip: If you have EasyCodingStandard, you can start your set with [`ecs-after-rector.yaml`](/ecs-after-rector.yaml).
2020-01-20 20:16:36 +01:00
## Try Rector Online
2020-03-21 11:41:11 +01:00
No time to try Rector locally?
2020-01-20 20:16:36 +01:00
2020-03-21 11:41:11 +01:00
We have **[an online demo](https://getrector.org/demo) just for you!**
2020-01-20 20:16:36 +01:00
2017-07-15 19:20:20 +02:00
## Install
```bash
composer require rector/rector --dev
2017-07-15 19:20:20 +02:00
```
2020-03-21 11:41:11 +01:00
**Having conflicts during `composer require` or on run?**
2019-12-27 20:04:34 +01:00
- Use the [Rector Prefixed](https://github.com/rectorphp/rector-prefixed)
2020-03-21 11:41:11 +01:00
**Using a different PHP version than Rector supports?**
2019-12-27 20:04:34 +01:00
2019-10-25 18:11:11 -07:00
- Use the [Docker image](#run-rector-in-docker)
2019-11-08 17:49:03 +01:00
## Running Rector
2020-01-09 16:58:20 +01:00
### A. Get Started
Try the demo and get familiar with rector
2020-01-09 17:02:33 +01:00
- [Rector demo](https://github.com/rectorphp/demo)
- [Rector training](https://github.com/rectorphp/rector-training)
2020-01-09 16:58:20 +01:00
### B. Prepared Sets
2019-11-08 17:49:03 +01:00
Featured open-source projects have **prepared sets**. You can find them in [`/config/set`](/config/set) or by running:
```bash
vendor/bin/rector sets
```
2020-01-10 09:43:15 +01:00
Let's say you pick the [`symfony40`](/config/set/symfony) set and you want to upgrade your `/src` directory:
2019-11-08 17:49:03 +01:00
```bash
# show a list of known changes in Symfony 4.0
vendor/bin/rector process src --set symfony40 --dry-run
```
```bash
# apply upgrades to your code
vendor/bin/rector process src --set symfony40
```
Some sets, such as [`code-quality`](/config/set/code-quality) can be
used on a regular basis. You can include them in your `rector.yaml` to
run them by default:
```yaml
# rector.yaml
2019-11-22 16:10:19 +01:00
parameters:
sets:
- 'code-quality'
- 'php71'
- 'php72'
- 'php73'
2019-11-08 17:49:03 +01:00
```
2020-01-09 16:58:20 +01:00
### C. Custom Sets
2019-11-08 17:49:03 +01:00
2020-03-21 11:41:11 +01:00
1. Create a `rector.yaml` configuration file with your desired Rectors or provide another configuration file with `--config`:
2019-11-08 17:49:03 +01:00
```yaml
services:
2020-03-20 21:10:12 +01:00
Rector\Core\Rector\Architecture\DependencyInjection\AnnotatedPropertyInjectToConstructorInjectionRector:
2019-11-08 17:49:03 +01:00
$annotation: "inject"
```
2. Run Rector on your `/src` directory:
```bash
vendor/bin/rector process src --dry-run
# apply
vendor/bin/rector process src
```
## Features
### Extra Autoloading
2020-03-21 11:41:11 +01:00
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:
2018-02-09 01:16:54 +01:00
```bash
2018-02-08 15:27:14 +01:00
vendor/bin/rector process ../project --autoload-file ../project/vendor/autoload.php
```
2020-03-21 11:41:11 +01:00
Or use a `rector.yaml` configuration file:
```yaml
2019-02-03 18:46:45 +01:00
# rector.yaml
parameters:
autoload_paths:
2018-11-09 14:58:49 +01:00
- 'vendor/squizlabs/php_codesniffer/autoload.php'
- 'vendor/project-without-composer'
```
2019-11-08 13:08:42 +01:00
### Exclude Paths and Rectors
2019-01-18 12:41:07 +01:00
2018-11-09 14:58:49 +01:00
You can also **exclude files or directories** (with regex or [fnmatch](http://php.net/manual/en/function.fnmatch.php)):
```yaml
2019-02-03 18:46:45 +01:00
# rector.yaml
parameters:
exclude_paths:
- '*/src/*/Tests/*'
```
You can use a whole ruleset, except one rule:
2019-01-18 12:41:07 +01:00
```yaml
2019-02-03 18:46:45 +01:00
# rector.yaml
2019-01-18 12:41:07 +01:00
parameters:
exclude_rectors:
- 'Rector\CodeQuality\Rector\If_\SimplifyIfReturnBoolRector'
```
2019-12-29 13:00:38 +01:00
Do you want to skip just specific line with specific rule?
Use `@noRector \FQN name` annotation:
```php
class SomeClass
{
/**
* @noRector \Rector\DeadCode\Rector\ClassMethod\RemoveEmptyClassMethodRector
*/
public function foo()
{
/** @noRector \Rector\DeadCode\Rector\Plus\RemoveDeadZeroAndOneOperationRector */
round(1 + 0);
}
}
```
### Filter Rectors
2020-01-15 03:11:11 +01:00
If you have a configuration file for Rector including many sets and Rectors, you might want at times to run only a single Rector from them. The `--only` argument allows that, for example :
```bash
2020-01-14 20:54:38 +01:00
vendor/bin/rector process --set solid --only "Rector\SOLID\Rector\Class_\FinalizeClassesWithoutChildrenRector" src/
```
2020-01-14 20:54:38 +01:00
Will only run `Rector\SOLID\Rector\Class_\FinalizeClassesWithoutChildrenRector`.
2020-01-14 21:46:19 +01:00
Please note that the backslash in the Rector's fully-qualified class name needs to be properly escaped (by surrounding the string in double quotes).
2019-11-08 13:08:42 +01:00
### 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:
2019-02-23 14:03:07 +01:00
```yaml
2019-10-12 17:51:07 +02:00
# rector.yaml
2019-02-23 14:03:07 +01:00
parameters:
php_version_features: '7.2' # your version is 7.3
2019-02-23 14:03:07 +01:00
```
2019-11-10 18:40:16 +01:00
### Paths
If you're annoyed by repeating paths in arguments, you can move them to config instead:
```yaml
# rector.yaml
parameters:
paths:
- 'src'
- 'tests'
```
2019-11-08 13:08:42 +01:00
### Import Use Statements
2020-04-04 22:59:33 +02:00
FQN classes are not imported by default. If you don't want to do it manually after every Rector run, enable it by:
2019-10-12 17:51:07 +02:00
```yaml
# rector.yaml
parameters:
2019-12-20 07:40:36 +01:00
auto_import_names: true
2019-10-12 17:51:07 +02:00
```
2019-12-20 07:40:36 +01:00
You can also fine-tune how these imports are processed:
```yaml
# rector.yaml
parameters:
2019-12-20 07:40:36 +01:00
# 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`.
```bash
vendor/bin/rector process src --match-git-diff
```
This option is useful in CI with pull-requests that only change few files.
2019-12-16 15:45:37 +01:00
### Symfony Container
To work with some Symfony rules, you now need to link your container XML file
```yaml
# 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](/docs/AllRectorsOverview.md).
2019-10-25 18:11:11 -07:00
Let's say we want to **change method calls from `set*` to `change*`**.
```diff
$user = new User();
-$user->setPassword('123456');
+$user->changePassword('123456');
```
### 1. Create a New Rector and Implement Methods
Create a class that extends [`Rector\Core\Rector\AbstractRector`](/src/Rector/AbstractRector.php). 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
2019-10-13 07:59:52 +02:00
<?php
declare(strict_types=1);
2020-01-18 00:45:51 +01:00
namespace Utils\Rector;
use Nette\Utils\Strings;
use PhpParser\Node;
use PhpParser\Node\Identifier;
use PhpParser\Node\Expr\MethodCall;
use Rector\Core\Rector\AbstractRector;
use Rector\Core\RectorDefinition\CodeSample;
use Rector\Core\RectorDefinition\RectorDefinition;
final class MyFirstRector extends AbstractRector
{
/**
* @return string[]
*/
public function getNodeTypes(): array
{
2020-03-21 11:41:11 +01:00
// what node types are we looking for?
2019-05-03 15:48:22 +02:00
// 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
{
2019-03-29 10:27:11 +01:00
// we only care about "set*" method names
2020-01-14 18:59:15 +01:00
if (! $this->isName($node->name, '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;
}
2020-01-18 00:45:51 +01:00
/**
* From this method documentation is generated.
*/
public function getDefinition(): RectorDefinition
{
return new RectorDefinition(
'Change method calls from set* to change*.', [
new CodeSample(
// code before
'$user->setPassword("123456");',
// code after
'$user->changePassword("123456");'
),
]
);
}
}
```
2020-03-21 11:41:11 +01:00
This is how the file structure should look like:
2020-01-18 00:45:51 +01:00
```bash
/src/YourCode.php
/utils/Rector/MyFirstRector.php
rector.yaml
composer.json
```
We also need to load Rector rules in `composer.json`:
```json
{
"autoload": {
"psr-4": {
"App\\": "src"
2020-01-18 01:06:59 +01:00
}
2020-01-18 00:45:51 +01:00
},
"autoload-dev": {
"psr-4": {
"Utils\\": "utils"
2020-01-18 01:06:59 +01:00
}
2020-01-18 00:45:51 +01:00
}
}
```
2020-03-21 11:41:11 +01:00
After adding this to `composer.json`, be sure to reload Composer's class map:
2020-01-18 00:45:51 +01:00
```bash
composer dump-autoload
```
### 2. Register It
```yaml
# rector.yaml
services:
2020-01-18 00:45:51 +01:00
Utils\Rector\MyFirstRector: ~
```
2019-05-03 15:48:22 +02:00
### 3. Let Rector Refactor Your Code
2020-03-21 11:41:11 +01:00
The `rector.yaml` configuration is loaded by default, so we can skip it.
2020-01-18 00:45:51 +01:00
```bash
# see the diff first
vendor/bin/rector process src --dry-run
# if it's ok, apply
vendor/bin/rector process src
```
That's it!
2020-03-21 11:41:11 +01:00
### Generating a Rector Rule
2020-01-18 00:45:51 +01:00
2020-01-18 01:06:59 +01:00
Do you want to save time with making rules and tests?
2020-01-18 00:45:51 +01:00
2020-03-21 11:41:11 +01:00
Use [the `create` command](/docs/RectorRecipe.md).
2020-01-18 00:45:51 +01:00
2017-12-28 17:58:35 -02:00
## More Detailed Documentation
2017-10-15 11:07:53 +02:00
2019-11-26 02:25:45 +01:00
- **[All Rectors Overview](/docs/AllRectorsOverview.md)**
- [How Does Rector Work?](/docs/HowItWorks.md)
2019-11-26 02:25:45 +01:00
- [PHP Parser Nodes Overview](/docs/NodesOverview.md)
- [Generate Rector from Recipe](/docs/RectorRecipe.md)
2017-10-15 11:07:53 +02:00
2017-12-28 17:58:35 -02:00
## How to Contribute
2017-07-15 19:20:20 +02:00
See [the contribution guide](/CONTRIBUTING.md).
2018-12-12 10:02:10 +01:00
## Run Rector in Docker
You can run Rector on your project using Docker:
2018-12-12 10:02:10 +01:00
```bash
2019-08-25 12:19:03 +02:00
docker run -v $(pwd):/project rector/rector:latest process /project/src --set symfony40 --dry-run
2019-03-11 16:12:27 +02:00
2019-10-25 18:11:11 -07:00
# Note that a volume is mounted from `pwd` (the current directory) into `/project` which can be accessed later.
2018-12-11 18:22:54 +01:00
```
Using `rector.yaml`:
```bash
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:
2019-10-18 20:54:54 +02:00
- [drupal8-rector/drupal8-rector](https://github.com/drupal8-rector/drupal8-rector) by [@mxr576](https://github.com/mxr576) for [Drupal](https://www.drupal.org/)
2019-10-24 18:04:18 -07:00
- [sabbelasichon/typo3-rector](https://github.com/sabbelasichon/typo3-rector) for [TYPO3](https://typo3.org/)