Rector で始める自動リファクタリング入門
はじめに
みなさん, リファクタリングはしていますでしょうか。
リファクタリングと一口に言っても様々な性格のものが存在しますが, その中でもある一定のルールに基づく機械的な作業が要求されるものがあるかと思います。
例えば,
- 全ての関数 A を関数 B に変えたい
- クラス A を継承している全てのクラスの親クラスをクラス B に変えたい
- コンストラクタ内でクラスをインスタンス化している処理を DI パターンに変えたい
などなど……。
小規模なものであれば手作業でおこなっても問題のないことが多いですが, 大規模になるとうっかりミスが発生しがちだったり単純作業ゆえの精神的な苦痛が伴うこともあったりなど, あまり好ましくありません。
本記事で紹介する Rector はそういった機械的な作業からエンジニアを開放するとてもすごいツールです。
是非本記事で Rector の基本的な使い方を覚え, 日々の業務を楽にしてみてください。
サンプルプロジェクトの構築
本記事では予め用意されたサンプルコードに対して Rector を実際に実行することで理解を深めていきたいと思います。
推奨環境
git clone
作業ディレクトリから以下のコマンドを実行しサンプルプロジェクトをローカル環境に構築します。
$ git clone git@github.com:YAhiru/rector-tutorial.git
$ cd rector-tutorial
サンプルプロジェクトの確認
サンプルプロジェクトは以下の構成になっています。
.
├── rector # Rector 用のディレクトリ
│ ├── src # 記事の終盤で作成する独自ルール用のディレクトリ
│ └── tests # 独自ルールのテストディレクトリ
├── src # サンプルのアプリケーションコードディレクトリ
└── tests # サンプルのアプリケーションコードのテストディレクトリ
理由は後述しますが Rector 用のディレクトリとサンプルのアプリケーションコードを分けています。
ここでいうアプリケーションコードとは Web アプリケーションであればコントローラーやエンティティなどに当たるもので, リファクタリングの対象となるコードです。
今回は src ディレクトリに単純なクラスを 1 つだけ用意しています。
rector ディレクトリは本記事の後半で実装する独自ルールのためのディレクトリとなっていますので, 最低限の設定のみでほぼ空の状態となっています。
インストール
Rector は composer req --dev rector/rector
を実行して利用する他に phar や docker などの形式が用意されています。
Rector の依存関係 を確認するとわかる通り依存するライブラリが非常に多いため, ルールを自作したいなどのニーズがない場合は phar あるいは docker 形式での利用をおすすめします。
今回は最終的にルールを自作したいため rector/rector を composer 経由でダウンロードするわけですが, 前述の通り依存関係が多いため既存のプロダクトにインストールすることができないといった問題の発生が予想されます。
そういった場合に有効なのが Rector 用のサブディレクトリを作成しその中で Rector 関連のコードを完結させることです。[1]
今回のサンプルプロジェクトでもそのアプローチを採用しています。
また、その他の構成については こちらの記事 も非常に参考になります。
では, 以下のコマンドで Rector のインストールをします。
$ cd rector
$ composer req rector/rector
ルールを適用してみる
それでは Rector を試していきたいと思います。
今回自動リファクタリングをしてみるファイルは src/User.php
です。
final class User
{
/** @var string */
private $screenName;
/** @var int */
private $age;
public function __construct(string $screenName, int $age)
{
$this->screenName = $screenName;
$this->age = $age;
}
// ...
}
User クラスのプロパティである $screenName
や $age
を見てみると Typed Property が適用されていないことがわかります。
Typed Property が適用されていない場合 PHP Doc に記述された型以外が代入された場合でもエラーが発生せず, 思わぬバグを引き起こす可能性を秘めています。
あなたの所属するチーム内でこのことが問題視されたという設定で, Rector を使ってこのクラスを自動リファクタリングしてみましょう。
Rector を実行する
Rector の実行は簡単で vendor/bin/rector process {{ディレクトリ}} --set {{ルールセット}}
のように, process コマンドに対してターゲットとなるディレクトリや適用したい ルールセット, ルール を渡せば良いだけです。
名前 | 説明 |
---|---|
ルール | リファクタリングの内容が定義された PHP のクラス |
ルールセット | 関心ごとが近い複数のルールがまとめられたもの |
今回は Typed Property だけを適用してくれればよいので, php74 というルールセットの中にある Rector\Php74\Rector\Property\TypedPropertyRector というルールのみを適用したいと思います。
rector ディレクトリ内で以下のコマンドを実行してみましょう。
$ vendor/bin/rector process ../src \
--set php74 \
--only 'Rector\Php74\Rector\Property\TypedPropertyRector'
修正されたファイルを確認する
コマンドを実行するとそれっぽさのある出力がなされたかと思いますが, 実際の User クラスを確認してみると以下のように $screenName
と $age
に Typed Property が適用されていることがわかります。
final class User
{
private string $screenName;
private int $age;
public function __construct(string $screenName, int $age)
{
$this->screenName = $screenName;
$this->age = $age;
}
// ...
}
どうですか!!!!!!!!すごくないですか!?!?!?!?!?!?!?!?(唐突な興奮)
Rector を使ってリファクタリングを自動化することで修正規模によっては工数を大幅に削減することが出来るため, あなたの上司もニッコリです。
ルールの自作
リファクタリングの要件はプロダクトによって様々なので Rector が用意してくれているルールだけでは要件を満たせないことがあります。
そういった場合に有効なのがルールの自作です。
独自のルールを作ることが出来ればプロダクト固有の要件であってもリファクタリングを自動化することができます。
今回はあなたの所属するチーム内で「PHPUnit のテストメソッドは, メソッド名に test
という prefix を付ける形式ではなく @test
アノテーションを使う形式にしたい」という要望が出たという設定で進めていきましょう。[2]
独自ルールのテストを書く
早速独自のルールを作っていきたいのですが, まずはどのようなコードをどのようにリファクタリングしたいのかということを明確にする必要があります。
Rector はテスト基盤も整っていますので, テストを書くことでルールのイメージを固めていきましょう。
ルールのテストでは必要なものが 2 つあります。
- テストクラス
- Fixture
テストクラス
ここでいうテストクラスとは PHPUnit\Framework\TestCase
を継承した任意のクラスのことです。
Rector には PHPUnit\Framework\TestCase
を拡張した Rector\Core\Testing\PHPUnit\AbstractRectorTestCase
[3] が用意されており, これによってルールのテストがとても簡単になるため今回はこれを利用します。
rector ディレクトリ内で以下のコマンドを実行してテストクラス用のファイルを作成します。
$ mkdir -p tests/AddTestAnnotationRector
$ touch tests/AddTestAnnotationRector/AddTestAnnotationRectorTest.php
ファイルが作成されたら, ファイルに以下の内容を書き込みます。
<?php
declare(strict_types=1);
namespace Yahiru\RectorTutorialRector\AddTestAnnotationRector;
use Iterator;
use Rector\Core\Testing\PHPUnit\AbstractRectorTestCase;
use Symplify\SmartFileSystem\SmartFileInfo;
use Yahiru\RectorTutorialRector\AddTestAnnotationRector;
final class AddTestAnnotationRectorTest extends AbstractRectorTestCase
{
/**
* @dataProvider provideData()
*/
public function test(SmartFileInfo $fileInfo) : void
{
$this->doTestFileInfo($fileInfo);
}
/**
* @return Iterator<SmartFileInfo>
*/
public function provideData() : Iterator
{
return $this->yieldFilesFromDirectory(__DIR__ . '/Fixture');
}
protected function getRectorClass() : string
{
return AddTestAnnotationRector::class;
}
}
getRectorClass()
はテスト対象となるルールのクラス名を返却します。
protected function getRectorClass(): string
{
return AddTestAnnotationRector::class;
}
ここで返却したルールを Rector\Core\Testing\PHPUnit\AbstractRectorTestCase
内でよしなに扱ってくれます。
AddTestAnnotationRector
クラスはまだ存在していませんが, テストを実装した後に作成する予定です。
provideData()
はこの後作成する予定の Fixture ファイルを読み込み, test()
は読み込まれた Fixture を利用してテストを実行します。
/**
* @dataProvider provideData()
*/
public function test(SmartFileInfo $fileInfo): void
{
$this->doTestFileInfo($fileInfo);
}
/**
* @return Iterator<SmartFileInfo>
*/
public function provideData(): Iterator
{
return $this->yieldFilesFromDirectory(__DIR__ . '/Fixture');
}
Fixture
Fixture とは, 以下のフォーマットで リファクタリング前のコード と リファクタリング後のコード が記述されたファイルのことです。
<?php
リファクタリング前のコード
?>
-----
<?php
リファクタリング後のコード
?>
実際の Fixture を見た方が理解が早いので, 早速 Fixture を作ってみましょう。
rector ディレクトリ内で以下のコマンドを実行してファイルを作成します。
$ mkdir -p tests/AddTestAnnotationRector/Fixture
$ touch tests/AddTestAnnotationRector/Fixture/fixture.php.inc
今回は test
という prefix がついているテストメソッドを @test
アノテーション形式に変換するというのが要件ですので, 作成したファイルに以下の内容を書き込みます。
<?php
namespace Yahiru\RectorTutorialRector\AddTestAnnotationRector\Fixture;
class SomeTest extends \PHPUnit\Framework\TestCase
{
public function testSome() : void
{
// do test
}
}
?>
-----
<?php
namespace Yahiru\RectorTutorialRector\AddTestAnnotationRector\Fixture;
class SomeTest extends \PHPUnit\Framework\TestCase
{
/**
* @test
*/
public function some() : void
{
// do test
}
}
?>
書き込んだ内容が前述のフォーマット通りになっていることを確認してください。
使用しているエディターによっては上記のコードをコピペした際にリファクタリング前と後の区切りを表す -----
の直前にスペースが入り込むことがあるので注意してください。
作成した Fixture の差分は以下の通りで, テストメソッドが @test
アノテーション形式に変わっています。
+ /**
+ * @test
+ */
+ public function some() : void
- public function testSome() : void
{
// do test
}
注意点
Fixture を作成する上での重要な注意点ですが, Rector はリファクタリング対象のコードを動的に読み込みます。
つまり今作成した Fixture に定義されているクラスも読み込まれるということなので, Fixture にうっかり namespace を書き忘れてしまうと, 他のテストの Fixture や既存クラスとクラス名が衝突する可能性が増します。
なので絶対に Fixture には namespace を書くようにしましょう。
Fixture を複数用意する
テストの準備自体はこれで完了ですが, テスト項目が足りていないのでもう少し Fixture を増やしたいと思います。
今回の独自ルールにおいて, メソッドがリファクタリング対象であると判断する基準は以下とします。
- クラスが
PHPUnit\Framework\TestCase
を継承していること - メソッド名が
test
で始まっていること - メソッドの可視性が public であること
正常系は先ほどの Fixture でテストできているので, 次は上記の条件以外ではリファクタリングされないことを保証する Fixture を追加します。
rector ディレクトリ内で以下のコマンドを実行してファイルを作成してください。
$ touch tests/AddTestAnnotationRector/Fixture/{no-test-prefix.php.inc,not-public-method.php.inc,not-test-class.php.inc}
コードの変更がない場合の Fixture はリファクタリング後のコードを省くことが可能ですので, それぞれのファイルに以下の内容を書き込みんでください。
<?php
namespace Yahiru\RectorTutorialRector\AddTestAnnotationRector\Fixture;
class NotTestPrefix extends \PHPUnit\Framework\TestCase
{
public function noPrefix() : void
{
}
}
<?php
namespace Yahiru\RectorTutorialRector\AddTestAnnotationRector\Fixture;
class NotPublicMethodTest extends \PHPUnit\Framework\TestCase
{
protected function testProtected() : void
{
}
private function testPrivate() : void
{
}
}
<?php
namespace Yahiru\RectorTutorialRector\AddTestAnnotationRector\Fixture;
class NotTest
{
public function testSome() : void
{
}
}
Fixture の準備はこれで完了です。
蛇足ですが, テストしたい内容を明確にするために Fixture は適切な粒度で分けることを意識すると良いでしょう。
独自ルールを作る
次は独自ルールを作成します。
ルールは基本的に Rector\Core\Rector\AbstractRector
を継承して作成します。
rector ディレクトリ内で以下のコマンドを実行してファイルを作成してください。
$ touch src/AddTestAnnotationRector.php
作成したファイルに以下の内容を書き込んでください。
<?php
declare(strict_types=1);
namespace Yahiru\RectorTutorialRector;
use PhpParser\Node;
use PhpParser\Node\Stmt\ClassMethod;
use PHPUnit\Framework\TestCase;
use Rector\Core\Rector\AbstractRector;
use Rector\Core\RectorDefinition\CodeSample;
use Rector\Core\RectorDefinition\RectorDefinition;
use Rector\NodeTypeResolver\Node\AttributeKey;
final class AddTestAnnotationRector extends AbstractRector
{
public function getDefinition() : RectorDefinition
{
return new RectorDefinition('Add @test annotation', [
new CodeSample(
<<<'CODE_SAMPLE'
class SomeTest extends \PHPUnit\Framework\TestCase
{
public function testSome() : void
{
// do test
}
}
CODE_SAMPLE
,
<<<'CODE_SAMPLE'
class SomeTest extends \PHPUnit\Framework\TestCase
{
/**
* @test
*/
public function some() : void
{
// do test
}
}
CODE_SAMPLE
),
]);
}
/**
* @phpstan-return array<class-string<Node>>
*
* @return array<string>
*/
public function getNodeTypes() : array
{
return [ClassMethod::class];
}
/**
* @param ClassMethod $node
*/
public function refactor(Node $node) : ?Node
{
if (! $this->shouldRefactor($node)) {
return null;
}
$phpDocInfo = $node->getAttribute(AttributeKey::PHP_DOC_INFO);
if ($phpDocInfo === null) {
$phpDocInfo = $this->phpDocInfoFactory->createEmpty($node);
}
$phpDocInfo->addBareTag('@test');
$testName = \lcfirst(
(string) \preg_replace('/\Atest/', '', (string) $this->getName($node))
);
$node->name = new Node\Identifier($testName);
return $node;
}
private function shouldRefactor(ClassMethod $node) : bool
{
$class = $node->getAttribute(AttributeKey::CLASS_NODE);
return $node->isPublic()
&& $this->isName($node, 'test*')
&& $this->isObjectType($class, TestCase::class);
}
}
getDefinition
getDefinition()
はリファクタリング前後のイメージを返します。
public function getDefinition() : RectorDefinition
{
return new RectorDefinition('Add @test annotation', [
new CodeSample(
<<<'CODE_SAMPLE'
class SomeTest extends \PHPUnit\Framework\TestCase
{
public function testSome() : void
{
// do test
}
}
CODE_SAMPLE
,
<<<'CODE_SAMPLE'
class SomeTest extends \PHPUnit\Framework\TestCase
{
/**
* @test
*/
public function some() : void
{
// do test
}
}
CODE_SAMPLE
),
]);
}
独自ルールにおいて getDefinition
に正確な内容を記述することは必須ではないですが, ルールの利用者がルールの性質を理解する手助けとなるので書いておいて損はないでしょう。
getNodeTypes
getNodeTypes()
はリファクタリング対象の Node クラスの配列を返却します。
public function getNodeTypes() : array
{
return [ClassMethod::class];
}
Node とは Rector 内部で使用されている nikic/php-parser によって AST (抽象構文木) にパースされた結果の各要素のことです。
今回はクラスメソッド以外には興味がないので PhpParser\Node\Stmt\ClassMethod
だけを指定しています。
Node の一覧はこちらから確認できます。
refactor
refactor()
はルールの核となるメソッドです。
このメソッドに渡された $node
を書き換えることでその内容がファイルに反映されます。
また, スキップする場合は null を返却します。
/**
* @param ClassMethod $node
*/
public function refactor(Node $node) : ?Node
{
if (! $this->shouldRefactor($node)) {
return null;
}
// do refactor
return $node;
}
今回は getDefinition()
で PhpParser\Node\Stmt\ClassMethod
のみを指定しているため, Rector によって refactor()
には PhpParser\Node\Stmt\ClassMethod
のインスタンスのみが渡されることが保証されています。
なので PHPDoc は@param PhpParser\Node\Stmt\ClassMethod $node
とし, $node
は PhpParser\Node\Stmt\ClassMethod
のインスタンスであることを前提にロジックを組み立てて構いません。
public function refactor(Node $node) : ?Node
{
// こういうことはしなくて良い
if (! $node instanceof ClassMethod) {
return null;
}
}
クラスメソッドであれば何でもリファクタリングしていいというわけではないので, refactor()
の最初にブロック文を実装しています。
public function refactor(Node $node) : ?Node
{
if (! $this->shouldRefactor($node)) {
return null;
}
// ...
}
private function shouldRefactor(ClassMethod $node) : bool
{
// クラスメソッドが実装されているクラス情報を取得
$class = $node->getAttribute(AttributeKey::CLASS_NODE);
return
// メソッドの可視性が public かどうか
$node->isPublic()
// メソッド名が `test` から始まっているかどうか
&& $this->isName($node, 'test*')
// メソッドが実装されているクラスが `PHPUnit\Framework\TestCase` を継承しているかどうか
&& $this->isObjectType($class, TestCase::class);
}
shouldRefactor()
はリファクタリングをすべきかどうかを判断するために実装したメソッドで, AddTestAnnotationRector
クラス固有のものです。
ブロック文を抜けたらコードの修正に相当するロジックを実行し $node
に変更を加えます。
public function refactor(Node $node) : ?Node
{
// ...
$phpDocInfo = $node->getAttribute(AttributeKey::PHP_DOC_INFO);
if ($phpDocInfo === null) {
$phpDocInfo = $this->phpDocInfoFactory->createEmpty($node);
}
$phpDocInfo->addBareTag('@test');
$testName = \lcfirst(
(string) \preg_replace('/\Atest/', '', (string) $this->getName($node))
);
$node->name = new Node\Identifier($testName);
return $node;
}
まず最初に PHP Doc に @test
アノテーションを追加する処理をしています。
// メソッドの PHP Doc を取得
$phpDocInfo = $node->getAttribute(AttributeKey::PHP_DOC_INFO);
if ($phpDocInfo === null) {
// PHP Doc がない場合は空の PHP Doc を作成する
$phpDocInfo = $this->phpDocInfoFactory->createEmpty($node);
}
$phpDocInfo->addBareTag('@test'); // PHP Doc に `@test` タグを追加する
次に $this->getName($node)
で取得したメソッド名から新しいメソッド名を生成し, 設定し直しています。
// 元のメソッド名から `test` prefix を削除し, 1文字目を小文字に変更した文字列
$testName = \lcfirst(
(string) \preg_replace('/\Atest/', '', (string) $this->getName($node))
);
// `$testName` を新しいメソッド名として設定しなおす
$node->name = new Node\Identifier($testName);
最後に $node
を返却することで変更を Rector に知らせて完了です。
return $node;
refactor()
の挙動をより理解したい場合は nikic/php-parser
の Walking the AST を読むことをオススメします。
作成したルールをテストする
それではルールが問題なく実装できているか確認しましょう。
rector ディレクトリ内で以下のコマンドを実行して先ほど作成したテストを走らせてください。
$ composer test
エラーが発生していなければ OK です。
テストが落ちた場合は Fixture の内容が記事の内容と一致しているか改めて確認してください。
独自ルールを実行する
自作したルールを実行するためには, コンフィグから Rector にルールを登録する必要があります。
rector ディレクトリ内で以下のコマンドを実行してコンフィグファイルを作成してください。
$ vendor/bin/rector init
rector.php
というファイルが rector ディレクトリに作成されたかと思うので, 作成されたファイルを以下の内容で書き換えてください。
<?php
declare(strict_types=1);
use Symfony\Component\DependencyInjection\Loader\Configurator\ContainerConfigurator;
return static function (ContainerConfigurator $containerConfigurator) : void {
$services = $containerConfigurator->services();
$services->set(\Yahiru\RectorTutorialRector\AddTestAnnotationRector::class);
};
ContainerConfigurator
についての詳しい使い方は Symfony のドキュメント を参照していただければと思いますが, $services->set()
の部分でルールを Rector に登録しています。
config の作成が完了したら以下のコマンドで Rector を実行します。
config ファイルで登録されたルールはオプションで渡さなくても有効になるので, 引数はディレクトリの指定のみで OK です。
$ vendor/bin/rector process ../tests
それっぽさのある出力がなされたかと思いますが, 実際に変更されたファイルを見てみましょう。
tests/UserTest.php
に以下のような差分が発生していれば成功です!
+ /**
+ * @test
+ */
+ public function getScreenName() : void
- public function testGetScreenName() : void
{
$this->assertSame('test user', $this->user->getScreenName());
}
+ /**
+ * @test
+ */
+ public function getAge() : void
- public function testGetAge() : void
{
$this->assertSame(20, $this->user->getAge());
}
}
Next Step
駆け足でいろいろと解説しましたが, 意外と簡単そうだなという感想を抱いた方も多いのではないでしょうか。
ここまでの知識で自力でルールを作ることも可能になっているかと思われますので, 是非次はご自身でルールを自作してみてください。
きっとより理解を深めることが出来ると思います!!
...とはいえ, そんなに都合よく作りたいルールがあるとは限りませんよね。
その場合は今回作成したルールをさらに改善してみてください。
実は本記事で作成したルールは, 現状の実装のままではあまり好ましくない挙動をするケースがあります。
たとえば以下のようなテストメソッドの場合です。
/**
* @test
*/
public function testFoo() : void
{
// do test
}
このようなテストメソッドに今回作成したルールを適用すると PHP Doc に @test
アノテーションが重複して書き込まれてしまいます。
なので, 既に @test
アノテーションがある場合は PHP Doc に変更を加えないような修正をしてみましょう。
独自ルールを作る際のコツ
本記事では最低限の説明になってしまっているので, 実際にルールを自作するとなると戸惑ってしまうことも多いかと思います。
しかも Rector のドキュメントはルールを自作するための情報が少なめのためドキュメントに頼ることもできません。[4]
そこで, ルールを自作するときに知っていると便利なことをいくつか共有したいと思います。
やりたい内容に近いことを行っているルールを探す
ドキュメントがあまりないので最良の教材は既存ルールのコードということになります。
幸い Rector には600を超えるルールが既に実装されているので, ドキュメントがなくとも何とかなります。
探し方としては, ルール一覧 からページ内検索をするのが早いと思います。
ルール一覧にはリファクタリング前後の差分が PHP コードとして掲載されているので, それを手掛かりにすると簡単に見つけることができます。
たとえば PHP Doc 関連のリファクタリングがしたい場合は, 上記のページからページ内検索で /**
のような PHP Doc っぽい文字列で検索してみると案外簡単に見つかります。
あまりにも大量にヒットしてしまう場合は差分の表現である +
や -
とセットで +␣␣␣␣/**
などと検索をすることで検索結果を絞ることができます。(␣
は半角スペースに読み替えてください)
お目当てのルールが見つかったあとはそのルールのコードを読むことで大体それっぽいことが出来るようになると思います。
よく使うメソッド・クラス
よく使うメソッドやクラスをパッと思いついた範囲で共有します。
この他には既存のルールのコードを読むことで便利なメソッドをいろいろと発見できるかと思われます。
クラス・メソッド | 説明 |
---|---|
Rector\Core\Rector\AbstractRecto::isName() | 第一引数の Node の名前が 第二引数の文字列と一致するか判定してくれる。第二引数には正規表現も使える |
Rector\Core\Rector\AbstractRecto::getName() | 第一引数に渡した Node の名前を返してくれる |
Rector\Core\Rector\AbstractRecto::getShortName() | FQN を渡すとショートネームを返してくれる |
Rector\Core\Rector\AbstractRecto::isObjectType() | 第一引数に渡した Node が第二引数のクラスとマッチするか判定してくれる(Class_ など型情報を持つ Node に使う) |
PhpParser\NodeAbstract::getAttribute() | Rector\NodeTypeResolver\Node\AttributeKey の定数を使うことで様々な情報を Node から取得できる |
Rector\Core\PhpParser\Node\BetterNodeFinder::find*() | Node の配列と検索条件を渡すと, 検索条件にマッチする Node だけ返してくれる |
Rector\Core\Rector\AbstractPHPUnitRector | PhpUnit 関連のルールを作るときに便利。今回作ったルールのテストメソッドの判定ルールも実はこのクラスで既に実装されてる。 |
Rector\BetterPhpDocParser\PhpDocInfo\PhpDocInfo::hasByName() | 引数に渡した文字列にマッチするタグが PhpDoc に含まれているかどうか判定してくれる |
Rector\BetterPhpDocParser\PhpDocInfo\PhpDocInfo::getTagsByName() | 引数に渡した文字列にマッチするタグを取得する |
参考になるリンク一覧
- ライフサイクル
- Walking the AST - nikic/php-parser
- ルールセット一覧
- ルール一覧
- config のオプション一覧
- ルールの設定変更
- Service Container
- 独自ルールの作り方
- generate コマンド
- Node 一覧
- テストについて
- Rector独自ルールのパッケージ運用
おわりに
Rector はすごい!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
筆者が所属する会社では Codeception のテストを PHPUnit に変換するルールを実装するなどして Rector の恩恵を受けています。
みなさんも Rector を活用してリファクタリングを楽にしていきましょう!
Discussion
大変参考になる記事でした。ありがとうございます。
ところで、2022年6月現在、独自ルールの作製手順に
rector generate
コマンドが登場したり、リファクタリング用のメソッドが一部変更されていたりとハンズオン部分の内容が古くなってしまっています。もし差し支えなければ
AddTestAnnotationRector.php
を作製するハンズオン部分を2022年版で書き直した記事を私の方で新たに執筆させて頂きたいのですがよろしいでしょうか?超長い記事なのに読んでいただいてありがとうございます!
書き直しは構いませんので、是非よろしくお願いします〜!
ありがとうございます。
2022年6月版を書かせていただきました。