開発ブログ

株式会社Nextatのスタッフがお送りする技術コラムメインのブログ。

電話でのお問合わせ 075-744-6842 ([月]-[金] 10:00〜17:00)

  1. top >
  2. 開発ブログ >
  3. PHP >
  4. Rectorでリファクタリングを試してみた
no-image

Rectorでリファクタリングを試してみた

最近ジメジメしており梅雨を実感しています。
それと同時に夏フェスなど夏が来るのが少し楽しみなヤマモトです。

先日リファクタリングをする際に、とても便利だったRectorについてメモ程度に皆さんにご紹介させていただきます。

 

環境

  • PHP: 8.1.8
  • Rector 0.17.1

Rectorについて

Rectorとは既存のPHPコードのリファクタリングやアップグレードを自動実行する便利なツールです。
開発を続けていると様々な場面でコードの書き方を変える必要が出てくることがあると思います。
膨大な量の書き換えを行うのは時間と手間がかかってしまいます。
そこでRectorを使用して設定したルールに従って自動で書き換えを実行することが可能です。



下記コマンドでまずインストールを行います。
composer require rector/rector --dev


インストールは以上ですが、少し注意点があります。
Rectorを既存のプロジェクトなどにインストールする場合にPHPStanを導入している場合にはバージョンによってインストールエラーとなるので注意してください。
自分の場合はPHPStanを最新バージョンにアップグレードしたところエラーは解消されました。

 

実際にRectorを使用する

基本的な使用方法としては
vendor/bin/rector process {{ディレクトリ}} --set {{ルールセット}} 
のように, process コマンドに対してターゲットとなるディレクトリや適用したい ルールセット, ルール を渡せば使用可能です。

ルールセットというものがあるのでそこから適用したいルールをコマンドで実行することで使用可能です。
今回は例としてphp74 というルールセットの中にある Rector\Php74\Rector\Property\TypedPropertyRectorというルールを実行するコマンドを記載します。
 
vendor/bin/rector process ../src \
    --set php74 \
    --only 'Rector\Php74\Rector\Property\TypedPropertyRector'
 

独自ルールの作成

既存のルールだけでは修正が行えないものに関しては独自のルールを作成してあげることでリファクタリングが可能となります。

今回は以下のようなスネークケースの変数を一括でローワーキャメルケースに変更してみたいと思います。
final class User
{
    public function run(): void
    {
        $screen_name1 = "名前1";
        $screen_name2 = "名前2";
        $screen_name3 = "名前3";
        $human_age1 = 19;
        $human_age2 = 20;
        $human_age3 = 21;
    }
}

変数を修正するためのRectorRulesというディレクトリを作成しその直下にこちらを参考に以下のようなルールファイルを作成します。
<?php

declare(strict_types=1);

namespace RectorRules;

use PhpParser\Comment\Doc;
use PhpParser\Node;
use PhpParser\Node\Expr\Variable;
use PhpParser\Node\Stmt\ClassMethod;
use PhpParser\Node\Stmt\Function_;
use Rector\Core\Php\ReservedKeywordAnalyzer;
use Rector\Core\Rector\AbstractRector;
use Symplify\RuleDocGenerator\ValueObject\CodeSample\CodeSample;
use Symplify\RuleDocGenerator\ValueObject\RuleDefinition;

/**
 * class UnderscoreToCamelCaseVariableNameRector
 */
final class UnderscoreToCamelCaseVariableNameRector extends AbstractRector
{
    /**
     * @see https://regex101.com/r/OtFn8I/1
     */
    private const PARAM_NAME_REGEX = '#(?<paramPrefix>@param\s.*\s+\$)(?<paramName>%s)#ms';

    private ReservedKeywordAnalyzer $reservedKeywordAnalyzer;

    public function __construct(
        ReservedKeywordAnalyzer $reservedKeywordAnalyzer
    ) {
        $this->reservedKeywordAnalyzer = $reservedKeywordAnalyzer;
    }

    public function getRuleDefinition(): RuleDefinition
    {
        return new RuleDefinition('Change under_score names to camelCase', [
            new CodeSample(
                <<<'CODE_SAMPLE'
                    final class SomeClass
                    {
                        public function run($a_b)
                        {
                            $some_value = $a_b;
                        }
                    }
                    CODE_SAMPLE
                ,
                <<<'CODE_SAMPLE'
                    final class SomeClass
                    {
                        public function run($aB)
                        {
                            $someValue = $aB;
                        }
                    }
                    CODE_SAMPLE
            ),
        ]);
    }

    /**
     * @return string[]
     */
    public function getNodeTypes(): array
    {
        return [Variable::class];
    }

    /**
     * @param Variable $node
     */
    public function refactor(Node $node): ?Node
    {
        $nodeName = $this->getName($node);

        $replaceUnderscoreToSpace = str_replace('_', ' ', $nodeName);
        $uppercaseFirstChar = ucwords($replaceUnderscoreToSpace);
        $camelCaseName = lcfirst(str_replace(' ', '', $uppercaseFirstChar));

        $node->name = $camelCaseName;

        return $node;
    }
}


getRuleDefinition() はリファクタリング前後のイメージを返します。
独自ルールにおいて getRuleDefinition() に正確な内容を記述することは必須ではないようですがリファクタリングの大まかな概要を記述しておくなどするといいかと思います。


refactor()内で変数を取得し、ローワーキャメルケースへの変換を行なっています。
getName()で変数が全て取得できるので、取得した変数を変更しています。


このルールがちゃんと動作しているか確認していこうと思います。

Rectorをインストールした際にできたrector.phpファイルに今回作成したルールを追加していきます。
<?php

use Rector\Config\RectorConfig;

return function (RectorConfig $rectorConfig) {
  $rectorConfig->rule(RectorRures\UnderscoreToCamelCaseVariableNameRector::class);
};
これで独自ルールを実行できるようになったはずです!


では以下のコマンドで独自ルールを実行していきます。
vendor/bin/rector process src --dry-run
 
1 file with changes
===================

1) src/User.php:3

    ---------- begin diff ----------
@@ @@
 {
     public function run(): void
     {
-        $screen_name1 = "名前1";
-        $screen_name2 = "名前2";
-        $screen_name3 = "名前3";
-        $human_age1 = 19;
-        $human_age2 = 20;
-        $human_age3 = 21;
+        $screenName1 = "名前1";
+        $screenName2 = "名前2";
+        $screenName3 = "名前3";
+        $humanAge1 = 19;
+        $humanAge2 = 20;
+        $humanAge3 = 21;
     }
 }
    ----------- end diff -----------

Applied rules:
 * UnderscoreToCamelCaseVariableNameRector

こちらのような結果となり、ちゃんと修正できていそうです。
dry-runを行なっているので実際のファイルは変更されていないので
dry-runを外した以下のコマンドを実行すればファイルも変更されました!
vendor/bin/rector process src
 

最後に

今回は簡単な変更だけでしたが、ルールの定義をもう少し複雑に行えば難しいリファクタリングも可能となります。
便利なものなので、もしよろしくければ皆さんも使ってみてください。
読んでいただきありがとうございました。


参考リンク
https://zenn.dev/isana/articles/rector-tutorial-2022#rector%E3%82%92%E5%85%A5%E3%82%8C%E3%82%8B
https://zenn.dev/y_ahiru/articles/auto-refactor-with-rector#getnodetypes

 
  • posted by やまちゃん
  • PHP
TOPに戻る