Today Fortkle Learned.

知らないことの方が多いので今更調べています。さらに一歩先に行けたら嬉しいです。

PHPアプリケーションのアップグレードとリファクタリングを楽にするrectorphp/rectorを試す

f:id:fortkle:20181217001149p:plain

この記事はコネヒト Advent Calendar 2018の16日目の記事です!

qiita.com

はじめに

PHPの静的解析周りのツールを調べていたら面白そうなツールがあったので試してみました。 それが Rector というツールです。

GitHub - rectorphp/rector: Instant Upgrades for PHP Applications

Rectorとは?

リポジトリのdescriptionから引用します。

Rector is a reconstructor tool - it does instant upgrades and instant refactoring of your code. I mean, why do it manually if 80 % can Rector handle for you?

instant upgradesinstant refactoring というのがポイントで、PHP CS Fixerのようにコードの自動整形/修正をしてくれるツールのようです。

どんなことができるの?

これもドキュメントにリストがあったので貼っておきます。

rector/AllRectorsOverview.md at master · rectorphp/rector · GitHub

気になるところでいうと PHP7.4 で導入が予定されている Typed Properties 2.0 の修正でしょうか。 コードで早速試してみましょう。

使ってみる

手元にCakePHP3系のプロジェクトがあったのでこれで試してみます。 まずはRectorをComposerでインストールします。

$ composer require rector/rector --dev

※既にPHPStanを使っているプロジェクトなどでは、まだ依存関係が複雑なためエラーになることが多いようです。簡単に試したいだけなので、 require-dev で conflictしているツールは暫定的に変えてインストールしました。

次に修正対象となるコードを用意します。こんな感じのプロパティを定義してみました。

diff --git a/src/Controller/AppController.php b/src/Controller/AppController.php
index 213f23d1..2rfewa31 100644
--- a/src/Controller/AppController.php
+++ b/src/Controller/AppController.php
@@ -16,6 +16,30 @@
 
 class AppController extends Controller
 {
+    /** @var int 数字の1 */
+    public $one = 1;
+
+    /**
+     * @var int 数字の2
+     */
+    public $two = 3;
+
+    /**
+     * 文字列の3
+     * @var string 文字列の3
+     */
+    public $three = '3';
+
+    /**
+     * 数字の配列
+     * @var int[] 数字の4~6
+     */
+    public $intList = [4, 5, 6];
+
+    /**
+     * @var Response Cake\Http\Responseクラスのインスタンス
+     */
+    public $response;

これで準備完了です。 Rector は rector コマンドで実行します。引数にルール(Rector)と検査対象のパスを指定することができるようです。 今回は「Typed Properties 2.0」の対応を含んだ PHP7.4 向けのルールである php74 を指定します。コマンドは以下のとおりです。 ※ --dry-runを外すとコードが実際に修正されます

$ vendor/bin/rector process src/Controller/AppController.php --level php74 --dry-run

実行結果がこちらです。簡単にプロパティに型指定を付けることができました。

--- Original
+++ New
@@ -16,30 +16,21 @@

 class AppController extends Controller
 {
-    /** @var int 数字の1 */
-    public $one = 1;
+    public int $one = 1;

-    /**
-     * @var int 数字の2
-     */
-    public $two = 3;
+    public int $two = 3;

     /**
      * 文字列の3
-     * @var string 文字列の3
      */
-    public $three = '3';
+    public string $three = '3';

     /**
      * 数字の配列
-     * @var int[] 数字の5~7
      */
-    public $intList = [4, 5, 6];
+    public array $intList = [4, 5, 6];

-    /**
-     * @var Response Cake\Http\Responseクラスのインスタンス
-     */
-    public $response;
+    public Response $response;

@var を含む行を削除するようなのでコメントが消えてしまうのが悩ましいところですが、正しく型指定が追加されていることが分かりますね。スカラ値だけでなく自前のクラスなども対応しているようです。

どうやってコードを修正しているのか

RectorがどうやってPHPのコードを解析し、修正しているのか気になったので調べてみました。

ポイントは Rectorの composer.json にも依存関係が定義されている nikic/PHP-Parser です。 nikic/PHP-Parser はphpで書かれたphpのパーサーです。PHPのコードから構文木(AST)を構築するだけでなく、一部を書き換えたり、書き換えた構文木(AST)を逆にPHPのコードに戻す、といったことができます。Rectorはこの仕組みを使っています。

以下の記事がnikic/PHP-Parserについて詳しく書かれていて参考になったので載せておきます。

nikic/PHP-Parser入門 - Qiita

まだまだ発展途上という感じですが、裏側の仕組みをみると PHP-CS-Fixerと比べて柔軟なことができそうな予感がしたのでまた時間を見つけて触ってみようと思います。 というわけでRectorを試してみた、という記事でした。