2018-01-05 15:39:33 +01:00
# How Does Rector Work?
(Inspired by [*How it works* in BetterReflection ](https://github.com/Roave/BetterReflection/blob/master/docs/how-it-works.md ))
## 1. Finds all files and Load Configured Rectors
2019-08-29 22:44:30 +02:00
- The application finds files in source you provide and registered Rectors - from `--set` , `--config` or local `rector.yaml`
2018-01-05 15:39:33 +01:00
- Then it iterates all found files and applies relevant Rectors to them.
- *Rector* in this context is 1 single class that modifies 1 thing, e.g. changes class name
## 2. Parse and Reconstruct 1 File
2018-01-05 16:19:15 +01:00
The iteration of files, nodes and Rectors respects this life cycle:
2018-01-06 15:10:18 +01:00
2018-01-05 16:19:15 +01:00
```php
2018-08-15 16:10:47 +02:00
< ?php declare(strict_types=1);
use Rector\Contract\Rector\PhpRectorInterface;
use PhpParser\Parser;
/** @var SplFileInfo[] $fileInfos */
2018-01-05 16:19:15 +01:00
foreach ($fileInfos as $fileInfo) {
// 1 file => nodes
2018-08-15 16:10:47 +02:00
/** @var Parser $phpParser */
2019-05-14 23:36:24 +09:00
$nodes = $phpParser->parse(file_get_contents($fileInfo->getRealPath()));
2018-01-06 15:10:18 +01:00
// nodes => 1 node
2018-01-05 16:19:15 +01:00
foreach ($nodes as $node) { // rather traverse all of them
2018-08-15 16:10:47 +02:00
/** @var PhpRectorInterface[] $rectors */
2018-01-05 16:19:15 +01:00
foreach ($rectors as $rector) {
2018-08-15 16:10:47 +02:00
foreach ($rector->getNodeTypes() as $nodeType) {
if (is_a($node, $nodeType, true)) {
$rector->refactor($node);
}
2018-01-05 16:19:15 +01:00
}
}
}
}
```
2018-01-05 15:39:33 +01:00
### 2.1 Prepare Phase
2018-08-15 16:10:47 +02:00
- File is parsed by [`nikic/php-parser` ](https://github.com/nikic/PHP-Parser ), 4.0 that supports writing modified tree back to a file
2018-01-05 15:39:33 +01:00
- Then nodes (array of objects by parser) are traversed by `StandaloneTraverseNodeTraverser` to prepare it's metadata, e.g. class name, method node the node is in, namespace name etc. added by `$node->setAttribute(Attribute::CLASS_NODE, 'value')` .
2018-01-06 15:10:18 +01:00
### 2.2 Rectify Phase
2018-01-05 15:39:33 +01:00
- When all nodes are ready, applicies iterates all active Rector
2018-08-15 16:10:47 +02:00
- Each nodes is compared to `$rector->getNodeTypes()` method to see, if this Rector should do some work on it, e.g. is this class name called `OldClassName` ?
2018-01-05 15:39:33 +01:00
- If it doesn't match, it goes to next node.
- If it matches, the `$rector->reconstruct($node)` method is called
- Active Rector changes all what he should and returns changed node
2018-01-06 15:10:18 +01:00
### 2.2.1 Order of Rectors
- Rectors are run by they natural order in config, first will be run first.
E.g. in this case, first will be changed `@expectedException` annotation to method,
then a method `setExpectedException` to `expectedException` .
2018-08-15 16:10:47 +02:00
```yaml
2019-02-03 18:46:45 +01:00
# rector.yaml
2018-03-03 11:35:57 +01:00
services:
2018-06-02 13:29:48 +02:00
Rector\PHPUnit\Rector\ExceptionAnnotationRector: ~
2018-01-06 15:10:18 +01:00
2019-09-23 17:09:26 +02:00
Rector\Renaming\Rector\MethodCall\RenameMethodRector:
2018-03-03 11:35:57 +01:00
$perClassOldToNewMethods:
'PHPUnit\Framework\TestClass':
'setExpectedException': 'expectedException'
'setExpectedExceptionRegExp': 'expectedException'
2018-01-06 15:10:18 +01:00
```
2018-01-05 15:39:33 +01:00
### 2.3 Save File/Diff Phase
2018-01-06 15:10:18 +01:00
- When work on all nodes of 1 file is done, the file will be saved if it has some changes
2018-01-05 15:39:33 +01:00
- Or if the `--dry-run` option is on, it will store the *git-like* diff thanks to [GeckoPackages/GeckoDiffOutputBuilder ](https://github.com/GeckoPackages/GeckoDiffOutputBuilder )
- Then go to next file
## 3 Reporting
2018-01-06 15:10:18 +01:00
- After this Rector displays list of changed files
2018-02-01 07:12:22 -02:00
- Or with `--dry-run` option the diff of these files
2018-02-23 19:21:22 +01:00
### Similar Projects
2018-08-15 16:10:47 +02:00
- [ClangMR ](https://static.googleusercontent.com/media/research.google.com/en//pubs/archive/41342.pdf ) for C++ by Google (closed source) - almost idential workflow, developed independently though
2018-02-25 17:05:35 +01:00
- [facebook/jscodeshift ](https://github.com/facebook/jscodeshift ) for Javascript
2018-08-15 16:10:47 +02:00
- [silverstripe/silverstripe-upgrader ](https://github.com/silverstripe/silverstripe-upgrader ) for PHP CMS, Silverstripe
- [dereuromark/upgrade ](https://github.com/dereuromark/upgrade ) for PHP Framework, CakePHP