RectorでLaravelの古い書き方を自動で直した話!--max-changesで少しずつPRにする運用
🙌 結論から
Laravel のプロジェクトに古い書き方が残っているなら、Rector に直させるのがかなりラクです!
Rector は、PHP のコードを決まったルールで自動的に書き換えてくれるツールです。
Laravel 向けのルールは driftingly/rector-laravel というパッケージにまとまっていて、composer.json の Laravel のバージョンを見て、必要なルールを選んでくれます。
ただ、一気に全部かけると差分が数百ファイルになって、レビューできません(・_・;)
そこで私は、--filter と --max-changes で「1回のPRで見られる量」に分けて少しずつ直す運用にしています。
この2つは、9月に出た Rector 2.6.6 と 2.6.7 で入ったオプションです👍
👀 古い書き方が残り続ける問題
うちのチームの Laravel プロジェクトは、Laravel 8 のころから少しずつバージョンを上げてきました。
アップグレード自体は通っていても、コードの書き方は古いまま残っているところが多いんですよね・・・。
たとえば、こんなものです。
Requestファサードを static で呼んでいるコントローラーUser::whereEmail($email)のような、Eloquent のマジックメソッド頼みのクエリ- 型宣言の無いメソッド
動くので誰も直さないし、レビューで指摘すると「それ今回の修正と関係ないですよね」となる。。
新しく入った人が古い書き方をお手本にしてしまうのも、けっこう困っていました(´・ω・`)
人の手で直すと終わらないので、ルールで機械的に直せるところは Rector に任せることにしました🤔
🔧 Rectorとrector-laravelの入れ方
入れるのはこの2つです。
composer require --dev rector/rector driftingly/rector-laravel
rector-laravel は PHP 8.3 以上が前提で、執筆時点の最新は 2.6.2 でした。
設定ファイルは、プロジェクト直下に rector.php を置きます。
私の設定はこれです(`・ω・´)
<?php
declare(strict_types=1);
use Rector\Config\RectorConfig;
use RectorLaravel\Set\LaravelSetList;
return RectorConfig::configure()
->withPaths([
__DIR__ . '/app',
__DIR__ . '/routes',
__DIR__ . '/tests',
])
->withComposerBased(laravel: true)
->withSets([
LaravelSetList::LARAVEL_CODE_QUALITY,
LaravelSetList::LARAVEL_STATIC_TO_INJECTION,
]);
ポイントは withComposerBased(laravel: true) です。
以前は LaravelLevelSetList::UP_TO_LARAVEL_130 のように、対象のバージョンを自分で書く方法が主流でした。
今は README でも、composer.json から入っている Laravel のバージョンを読んで自動で選ぶこちらの書き方が勧められています。
Laravel を上げたときに rector.php を書き換え忘れる心配がないのが、かなりありがたいです😊
設定を書いたら、まず中身が正しいかだけ確かめます。
vendor/bin/rector validate-config
これは 2.6.7 で入ったコマンドで、ファイルを1つも処理せずに rector.php の設定ミスだけ見てくれます💡
✨ 私の運用は「少しずつPRにする」
ここが一番伝えたいところです!
最初に vendor/bin/rector process --dry-run を流したら、差分が300ファイルを超えました😭
これをそのまま1つの PR にしても、誰もちゃんと見られません。
なので今は、次の2つのオプションで1回の量を絞っています。
1. --filter でディレクトリやファイル名を絞る(2.6.6〜)
vendor/bin/rector process app --filter Controller --filter Admin
--filter は何回でも重ねられて、全部のパターンに一致したファイルだけが対象になります。
上の例だと「パスに Controller と Admin の両方を含むファイル」だけです。
2. --max-changes で1回の変更数に上限をつける(2.6.7〜)
vendor/bin/rector process app --filter Controller --max-changes=30
ルールが当たった数が上限に来たら、そこで止まります。
私は「1つのPRで30変更まで」と決めて、週に1本ずつ出しています🙌
この量ならレビューする側も10分くらいで見られるので、リファクタリングだけの PR でも嫌がられなくなりました(^^)
3. CI では dry-run だけ回す
GitHub Actions では、書き換えはせずに「Rector が直したい箇所が増えていないか」だけ見ています。
- name: Rector (dry-run)
run: vendor/bin/rector process --dry-run --no-progress-bar
2.6.7 から、TTY でない出力ではプログレスバーが出ず、色のエスケープ文字も出ないようになりました。
なので CI のログがかなり読みやすくなっています✅
機械で読みたい場合は --output-format=json にすると、どのルールが何行目に当たったかが付いてきます。
🤔 最初にハマったところ
Rector が直したあとのコードが、Pint の整形とけんかする
Rector は書き換えた部分のインデントや改行を、プロジェクトの整形ルールに合わせてくれるわけではありません。
最初は Rector の差分に、整形だけの変更が大量に混ざって読みづらかったです(T_T)
今は「Rector → vendor/bin/pint --dirty」の順で流すようにして、整形の差分を同じコミットで吸収しています。
LARAVEL_STATIC_TO_INJECTION は、テストが無いところに使わない
ファサードの static 呼び出しをコンストラクタインジェクションに直すセットです。
便利ですが、コンストラクタの引数が増えるので、手で new しているクラスがあると壊れます。
私はテストがあるディレクトリから順に --filter で当てていて、テストが無いところは後回しにしています( .. )
ルールの設定値を変えたのに結果が変わらない
古い Rector では、同じルールの設定値だけ変えても、キャッシュされた前回の結果が返ってくることがありました。
これは 2.6.5 で直っていて、設定値を変えるとキャッシュも作り直されます。
古いバージョンのまま使っている人は、--clear-cache を付けて流すか、先に Rector を上げるのが早いです👍
🔗 関連記事と使い分け
- Laravel 13のPHP属性:rector-laravel には、モデルやジョブの設定を Laravel 13 の属性に書き換えるルールも入っています。手で直す前に Rector で一括変換できるか試すのがおすすめです
- Larastanのキュー用ルール:Larastan は「間違いを見つける」、Rector は「書き方を直す」担当です。CI では Larastan → Rector(dry-run)の順で回しています
- PHP 8.5のパイプ演算子:新しい構文に寄せるときも、まず Rector の PHP セットで直せる範囲を見てから手を入れています
パパ系Webエンジニア〜愛用ガジェット一覧 🛍️
この記事を書いている作業環境のガジェットを楽天ROOMにまとめています ✨ 在宅エンジニアのデスク作りの参考にどうぞ 🙌
👍 まとめ
Rector は「一気に全部直す」より、--filter と --max-changes で少しずつ PR にする方が、チームで続けやすかったです。
withComposerBased(laravel: true) にしておけば、Laravel を上げたときに設定を触る必要もありません。
正直、最初は「自動で書き換えるツールなんて怖い・・・」と思っていましたが、dry-run で差分を見てから当てる流れにしたら不安はほぼ無くなりました(^o^)/
古い書き方が気になっている Laravel のプロジェクトがあるなら、まずは --dry-run で何件出るかだけ見てみてください🙌
※ バージョン番号・料金・機能は今後も変わる可能性があります。最新情報は公式サイトをご確認ください👀