前回紹介したmatch式 や Constructor Property Promotion のように新しい記法が導入されることでボイラープレートが駆逐されコードがより簡潔に読みやすくなります。しかし、長年運用されているプロジェクトなどでは書き換え必要な箇所が多く、導入するのに及び腰になってしまいがちです。Rectorを使うことでそんな億劫な作業が一瞬で完了するかもしれませんよ。
Rectorとは?
「Rector」とは、どんなPHPプロジェクトでも実行可能なPHPツールであり、瞬時にアップグレードや自動リファクタリングを実行できます。
という事で、まさにPHP8から導入されたsyntaxで書き換えたい、という私の要求にマッチしています。それらを自動で行なってくれるなら大助かりです。
現時点(2023/04/22)で ver 0.15.23 が最新で実行にはPHP7.2以上が必要となっています。
どんなツールか早速使って体感してみましょう。
インストール
新しく作成したLaravelのprojectにてインストールしました。
composer require rector/rector --dev
すると vendor/bin/rector
が追加されます。
vendor/bin/rector --version >> Rector 0.15.25
設定ファイルを追加
次に設定ファイルを(rector.php
)プロジェクトに追加します。
vendor/bin/rector init // rector.php を作成するか問われるので yes とタイプ No "rector.php" config found. Should we generate it for you? [yes]: > yes [OK] The config is added now. Re-run command to make Rector do the work!
プロジェクトのルートディレクトリに rector.php
が作成されました。
デフォルトでは以下の状態です。
<?php declare(strict_types=1); use Rector\CodeQuality\Rector\Class_\InlineConstructorDefaultToPropertyRector; use Rector\Config\RectorConfig; use Rector\Set\ValueObject\LevelSetList; return static function (RectorConfig $rectorConfig): void { $rectorConfig->paths([ __DIR__ . '/app', __DIR__ . '/bootstrap', __DIR__ . '/config', __DIR__ . '/lang', __DIR__ . '/public', __DIR__ . '/resources', __DIR__ . '/routes', __DIR__ . '/tests', ]); // register a single rule $rectorConfig->rule(InlineConstructorDefaultToPropertyRector::class); // define sets of rules // $rectorConfig->sets([ // LevelSetList::UP_TO_PHP_80 // ]); };
リファクタリングしたいパスは
$rectorConfig->paths([...]);
にて指定できます。
また、適用したい変更をrule
として指定します。
$rectorConfig->rule(InlineConstructorDefaultToPropertyRector::class); // 複数のruleをまとめて指定するならrules $rectorConfig->rules([ InlineConstructorDefaultToPropertyRector::class, InlineIfToExplicitIfRector::class ]);
Rectorで扱うリファクタリングは主に記法の統一なので、
「こういう時はこう書きましょう」というルールを定めるイメージですね。
Rules Overview にて指定可能なルールがまとめられていますので、ご確認を。
実践
前回紹介した Constructor Property Promotion について
リファクタリング可能か試してみましょう。
まず、以前の記事で使用した例と同じ Person.php を app/Models/
配下に作成します。
<?php namespace App\Models; class Person { public string $name; public int $age; public string $sex; public function __construct(string $name, int $age, string $sex) { $this->name = $name; $this->age = $age; $this->sex = $sex; } }
次に、rector.php
を以下のように書き換え設定します。
<?php declare(strict_types=1); use Rector\Config\RectorConfig; use Rector\Php80\Rector\Class_\ClassPropertyAssignToConstructorPromotionRector; return static function (RectorConfig $rectorConfig): void { // app 配下のみを対象にする $rectorConfig->paths([ __DIR__ . '/app', ]); // Constructor Property Promotion を適用するruleを追加 $rectorConfig->rule(ClassPropertyAssignToConstructorPromotionRector::class); };
Constructor Property Promotion に書き換えるruleはこちらにありました。
準備が整ったので書き換えてみましょう。
まずは--dry-run
を付けて実行します。
vendor/bin/rector process --dry-run
--dry-run
ではコード自体は変更されません。
変更前後の差分が表示されるので、それを見て意図通りの変更が適用されるか事前確認します。
1 file with changes =================== 1) app/Models/Person.php:3 ---------- begin diff ---------- @@ @@ class Person { - public string $name; - public int $age; - public string $sex; - - public function __construct(string $name, int $age, string $sex) + public function __construct(public string $name, public int $age, public string $sex) { - $this->name = $name; - $this->age = $age; - $this->sex = $sex; } } ----------- end diff ----------- Applied rules: * ClassPropertyAssignToConstructorPromotionRector (https://wiki.php.net/rfc/constructor_promotion https://github.com/php/php-src/pull/5291) [OK] 1 file would have changed (dry-run) by Rector
意図通りの変更が施されていますね。
問題無かったので今度は--dry-run
オプションを省いて実行します。
vendor/bin/rector process
Person.php
がリファクタリングされ以下となりました。
<?php namespace App\Models; class Person { public function __construct(public string $name, public int $age, public string $sex) { } }
まとめ
長くなってしまったのでRector導入編、ということで一旦ここで切ります。
今回の記事では掘り下げられなかったSet Listsについては次回以降の記事で紹介できればと思います。
今回は解説用なので1ファイルのみのリファクタリングとなりましたが、
大きいプロジェクトであれば数十数百のファイルにコマンド一発で変更が適用されるので
記法を置換する際にはとても便利なツールだと思います。
また、今回は古い記法を置換する目的で触ってみましたが、
例えばチームで開発している際に以前に紹介されたpintなどと同様に
コードスタイルを統一する目的でも活用できるのでは、と思います。
参照
Rectorでリファクタリングを自動化 その2
Rectorでリファクタリングを自動化 その3