2児のパパ系Webエンジニア
の開発日記
A Dad-of-Two Engineer's Development Diary

RectorでLaravelの古い書き方を自動で直した話!--max-changesで少しずつPRにする運用

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 で何件出るかだけ見てみてください🙌


※ バージョン番号・料金・機能は今後も変わる可能性があります。最新情報は公式サイトをご確認ください👀

参考になったらシェアしてもらえるとうれしいです🙌

Xでポスト Threads はてブ LINE