😇

Mago: PHP開発が爆速になる?次世代の静的解析ツールを試してみた

に公開

はじめに

PHPでの開発において、コードの品質を高く保つことは、プロジェクトの成功に欠かせない重要な要素です。
これまで、コードフォーマッタ、リンター、静的解析といったツールは、それぞれ別のものを組み合わせて使うのが一般的でした。しかし、今回ご紹介する Mago は、これらの機能をたった一つに統合した、PHP界に現れたちょっと革新的なツールチェーンです。

私自身、普段のPHP開発では、次のようなツールを愛用していました。

  • PHPStan: 頼れる静的解析ツール
  • PHP-CS-Fixer: コードを美しく整えるフォーマッタ

これらのツールに大きな不満はなかったのですが、心のどこかで「静的解析、もう少し速くならないかな…」「ツールの設定がバラバラで、ちょっと面倒だな…」と感じていたのも事実です。

そこで今回は、最近注目を集めている Mago という、Rustで書かれた爆速PHPツールチェーンを実際に試してみることにしました。

せっかくなので、PHPがどうやってRust製のパワフルなバイナリを使っているのか、その裏側も少し覗いてみたいと思います。

今回テストで作成したリポジトリはこちらになります。
https://github.com/takemo101/mago-example

Magoとは

Magoは、人気のプログラミング言語 Rust で実装された、PHPのための開発ツールです。
「とにかく速く!」をコンセプトにゼロから設計されており、他のどのツールよりも高速にコードの解析やフォーマットを実行します。

強力な静的アナライザー、自動修正も可能なリンター、そして独自の哲学を持つコードフォーマッター。これら全てが、たった一つのバイナリにギュッと詰まっています。

ざっくり言うと、PHPStan, PHP-CS-Fixer, Psalm といったツール界の”三種の神器”を一つにまとめたようなイメージです。
これは期待が高まりますね!

https://mago.carthage.software/

Setup

さっそくComposerでインストールして、初期設定をしてみましょう。

Composer経由でインストール

おなじみのコマンドを一発実行するだけです。

composer require --dev carthage-software/mago

これだけで、あなたの環境に最適化されたRust製の高速なバイナリがダウンロードされ、./vendor/bin/mago から使えるようになります。シンプルで良いですね。

初期化

インストールが終わったら、mago init コマンドで設定ファイル mago.toml を作ります。
まるで賢いアシスタントに質問されているかのように、対話形式でサクサク設定が進んでいきます。

./vendor/bin/mago init


 Mago

 ⬩ Welcome! Let's get you set up.

  ╭─ Step 1: Project Setup
  │
  │  Found `composer.json`. Use it to auto-configure project paths & PHP version? · yes
  │
  │  Reading composer.json...
  │  Project settings detected!
  ╰─
  ╭─ Step 2: Linter Configuration
  │
  │  The Linter checks your code for stylistic issues and inconsistencies.
  │  Use `composer.json` to auto-detect framework integrations? · yes
  │
  │  Detecting integrations from composer.json...
  │  Done!
  ╰─

  ...あとは流れに沿ってYes/Noと答えるだけ!...
  
  ✅ Configuration file created successfully!

  ╭─ 🎉 You're all set!
  │
  │  Mago is now configured for your project.
  │
  │  What's next?
  │    - Run `mago lint` to check for issues.
  │    - Run `mago analyze` to find type errors.
  │    - See formatting changes with `mago fmt --dry-run`.
  │
  │  Tip: Use the `--help` flag on any command for more options.
  │
  ╰─ For full documentation, visit: https://mago.carthage.software/

はい、完了です!
フォーマッタやリンターの細かいルールは、生成された mago.toml でいつでも調整できます。

使ってみる

それでは、Magoの主な機能を使ってみましょう。

1. Formatter(フォーマッター)

独自の哲学を持つコードフォーマッター。PSR-12規約にバシッと準拠させてくれるので、もうレビューでインデントの指摘に時間を取られることはありません。

# プロジェクト内のファイルを一括で美しく整形
./vendor/bin/mago fmt

# 「修正はしないで、どこが変わるかだけ教えて」という場合に
./vendor/bin/mago fmt --check

# 変更内容をプレビュー表示
./vendor/bin/mago fmt --dry-run

--dry-run を実行すると、差分が分かりやすく表示されます。便利!

diff of 'src/Synthesizer/Value/Cutoff.php':
--- original
+++ modified
@@ -12,36 +12,36 @@
  */
 final readonly class Cutoff
 {
-    /** 最小カットオフ周波数(Hz) */
-    public const float MIN = 20.0;
+       /** 最小カットオフ周波数(Hz) */
+       public const float MIN = 20.0;

...

2. Linter(リンター)

コードのスタイルに関する問題や、「なんだかこのコード、イケてない匂いがする…」といった"コードの匂い"を超高速で見つけてくれます。「神は細部に宿る」と言いますが、その細部をMagoがしっかりチェックしてくれます。

# プロジェクト全体をリント実行
./vendor/bin/mago lint

# 「未使用の変数」だけ、ピンポイントでチェックしたい時に
./vendor/bin/mago lint --only unused-variable 

問題が見つかると、どこがどう問題で、どうすれば良いか親切に教えてくれます。

warning[constant-type]: Class constant `MIN` is missing a type hint.
   ┌─ src/Synthesizer/Value/Cutoff.php:16:2
   │
16 │     public const MIN = 20.0;
   │     ^^^^^^^^^^^^^^^^^^^^^^^^ Class constant `MIN` is defined here
   │
   = Adding a type hint to constants improves code readability and helps prevent type errors.
   = Help: Consider specifying a type hint for `MIN`.

3. Analyzer(静的解析)

Magoの真骨頂とも言える、強力な静的解析エンジンです。コードを実行する前に、論理的なエラーや型の不一致といった潜在的なバグを発見します。実行時エラーで頭を抱える前に、Magoがそっと教えてくれる安心感は絶大です。

# 静的解析を実行して、バグの芽を摘む
./vendor/bin/mago analyze

エラーが見つかると、これもまた非常に分かりやすく指摘してくれます。

error[non-existent-class]: Class `Takemo101\MagoExample\Synthesizer\Value\InvalidArgumentException` not found.
   ┌─ src/Synthesizer/Value/Cutoff.php:27:23
   │
27 │             throw new InvalidArgumentException(sprintf(
   │                       ^^^^^^^^^^^^^^^^^^^^^^^^ `Takemo101\MagoExample\Synthesizer\Value\InvalidArgumentException` is not defined or cannot be autoloaded
   │
   = Help: Ensure the name is correct, including its namespace, and that it's properly defined and autoloadable.

4. Lexer & Parser (上級者向け)

PHPコードを「抽象構文木(AST)」という構造的なデータに変換する機能です。
普段はあまり使いませんが、ツールの内部動作に興味がある方には面白いかもしれません。

# コードの構造を覗いてみる
./vendor/bin/mago ast src/Synthesizer/Oscillator.php

Github Actionsに組み込む

もちろん、CI/CDのパイプラインにも簡単に組み込めます。
これで、プルリクエストごとにコード品質が自動でチェックされ、チーム全体の品質維持に貢献します。

https://mago.carthage.software/recipes/github-actions

PHPは、どうやってRustの力を借りている?

Magoの圧倒的なパフォーマンスは、Rustで書かれたネイティブバイナリのおかげです。
では、PHPからどうやってこの強力な助っ人を呼び出しているのでしょうか?

結論から言うと、PHPに標準で備わっている proc_open という関数を使っています。

https://github.com/carthage-software/mago/blob/dc333edb2613e427d4a850b8ba41ed529726e367/composer/bin/mago#L26-L52

Magoのスクリプトは、このproc_openを使ってバイナリを起動し、コマンドの引数を渡し、結果を受け取っています。

まとめ

Magoは、PHP開発における静的解析の体験を大きく変える可能性を秘めた、まさに革命的なプロジェクトです。

圧倒的なパフォーマンス

従来のツールと比べて 10倍から100倍近い速度向上 は伊達じゃありません。数分かかっていたCIのジョブが数秒で終わる世界...想像しただけでワクワクしますね。

Magoに乗り換える"おいしい"理由

  • 設定のシンプルさ: あちこちに散らばっていた設定ファイルが、mago.toml一つにまとまります。
  • 体験の一貫性: フォーマッタ、リンター、アナライザーが三位一体となり、一貫したルールでコードをチェックできます。
  • モダンな標準: PSR-12準拠はもちろん、最新のベストプラクティスが取り入れられています。

ベータ版としての現状と未来

現在はまだベータ版ですが、開発は非常に活発です。この技術的な優位性を考えると、近い将来、PHP開発における標準ツールの一つとなる可能性は非常に高いでしょう。

「速度は機能である」 —— Magoはこの哲学を体現しています。単なるツールの置き換えではなく、PHP開発の体験そのものを向上させてくれる存在です。

このスピードと快適さは、一度試してみる価値大アリです!

参考リンク

株式会社ソニックムーブ

Discussion