Rust製PHP静的解析ツール「phanalist」— 設定ゼロで14ルール即適用

タグ PHP静的解析RustphanalistCI/CDコード品質PHPStanGitHub ActionscolumnコラムlinuxLinuxGitHubオープンソースdenzyldick
🚀 今すぐ試せます! デモスクリプトをダウンロードして、解凍後にターミナルで bash ファイル名.sh を実行してください(中身を一度確認してから実行すると安心です)。 (macOS / Linux 環境が必要)

Rust製PHP静的解析ツール「phanalist」— 設定ゼロで14ルール即適用

ひとことでいうと

phanalist(ファナリスト)は、Rust(ラスト)という高速な言語で作られた PHP 向けの静的解析ツールです。静的解析とは、プログラムを実際に動かさずにソースコードを読んで問題を見つける仕組みのことです。設定ファイルを用意しなくても最初から 14 種類のルールでコードを自動チェックしてくれます。PHP を書いているエンジニアなら、インストール後すぐに使い始められます。チームの品質管理にも、個人のコード改善にも役立てられる実用的なツールです。


こんな人におすすめ

1. CI パイプラインでコード品質を自動チェックしたい開発チーム プルリクエスト(コード変更の申請)を出すたびに自動で品質ゲートをかけたい場合に向いています。SARIF(サリフ)形式という標準フォーマットで出力できるので、GitHub Actions や GitLab CI などの自動化環境にすんなり組み込めます。

2. 複雑になった PHP コードを整理したいエンジニア 「この関数、どこから直せばいいのか分からない…」という状況で役立ちます。サイクロマティック複雑度(関数の複雑さを数値化したもの)や NPath 複雑度(実行ルートの総数)を数値で表示してくれるので、優先して手を入れるべき箇所が一目でわかります。

3. PHPStan・Psalm などの解析ツールをすでに使っている方 phanalist は PHPStan や Psalm と競合しません。設計上の問題(Law of Demeter 違反など)を補う形で使えるため、複数のツールを組み合わせてより多角的な品質チェックができます。


インストール・使い方

ターミナル(文字を入力してパソコンに命令を送る画面)を開いて、以下のコマンドをコピー&ペーストするだけで進められます。

Step 1 — インストールスクリプトを実行する

curl --proto '=https' --tlsv1.2 -sSf \
  https://raw.githubusercontent.com/denzyldick/phanalist/main/bin/init.sh | sh

このコマンドは、インターネット上にある公式のインストール用スクリプトをダウンロードして実行します。スクリプトが自分の OS(Windows / Mac / Linux)と CPU の種類(x86_64 / aarch64)を自動で判定し、対応するバイナリ(実行ファイル)を取得してくれます。手動で選ぶ必要はありません。

Step 2 — インストールの確認

~/phanalist -V
# phanalist 1.0.0

~/phanalist はホームディレクトリ(ユーザーのファイル置き場)に配置されたバイナリを指します。バージョン番号が表示されれば準備完了です。

Step 3 — PHP プロジェクトを解析する

# カレントディレクトリ(今いるフォルダ)の ./src を対象に解析
~/phanalist

# ソースコードの場所を直接指定する場合
~/phanalist --src /path/to/your/php/src

初回実行時に phanalist.yaml という設定ファイルが自動で作られます。何も変えなくても 14 ルールが全て有効な状態でチェックが始まります。

Step 4 — 出力形式を選ぶ(CI 連携のとき)

# 機械が読みやすい JSON 形式で出力
~/phanalist --output-format json

# GitHub Code Scanning に対応した SARIF 形式で出力
~/phanalist --output-format sarif

JSON や SARIF 形式を選ぶと、他のツールやダッシュボードで解析結果を読み込みやすくなります。ふだん手元で確認するだけなら、デフォルトのテキスト形式のままで十分です。

Step 5 — 設定ファイルで細かく調整する(任意)

自動生成された phanalist.yaml を編集すると、ルールの有効・無効の切り替えや数値の変更ができます。

disable_rules:
  - E0000   # このルールIDを無効化

rules:
  E0007:
    max_parameters: 4   # メソッド引数の上限を 4 に変更
  E0009:
    max_complexity: 8   # サイクロマティック複雑度の閾値を 8 に変更

いきなり全ルールを適用するのが難しい場合は、enabled_rules に試したいルール ID だけを列挙することで段階的に導入できます。慣れてきたら disable_rules 方式に移行するとスムーズです。


ブラウザで試す

この記事にはブラウザ上で PHP コードを入力して、phanalist の解析結果をリアルタイムで確認できるデモが付いています。サンプルコードには空の catch ブロック(エラーを握りつぶす書き方)や、引数が多すぎるメソッドなど、複数のルール違反がわざと仕込まれています。どのルールが検出されるか、ぜひ手を動かして確かめてみてください。インストールなしで動作を体験できるので、「まず雰囲気だけ知りたい」という方にも最適です。


動かしてみた

リポジトリには ./phanalist バイナリがあらかじめ同梱されており、ダウンロード後すぐに実行できることを確認しました。

$ ./phanalist -V
phanalist 1.0.0

--output-format json オプションを指定すると、違反の一覧が JSON 形式で出力されます。ファイルに保存してスクリプトで加工したり、ダッシュボードツールに読み込んだりするのに使いやすい形です。リポジトリルートには phanalist.yaml の雛形も用意されており、デフォルト設定の全体像をすぐ確認できます。また Python 3.12 環境が利用可能な場合は、Gradio(グラジオ)というライブラリを使ってブラウザ上のインタラクティブなデモを組み立てることもできます。


実践のコツ — はじめの一歩

  • まず --summary-only フラグで全体像を把握する: ルールごとの違反件数だけをざっと一覧表示できます。大きなコードベースで「どのルールが一番たくさん引っかかっているか」を先に確認すると、どこから着手すればよいか判断しやすくなります。

  • CI では --quiet フラグで終了コードだけ見る: このフラグは標準出力への表示を抑制します。違反があれば終了コードが 0 以外になるので、「失敗したらビルドを止める」という判定だけしたいスクリプトに向いています。

  • ルールは少しずつ増やす: 既存プロジェクトに一度に全ルールを適用すると違反が大量に出て圧倒されることがあります。enabled_rules に E0007(引数過多)など目立つ 2〜3 個だけ書いて始め、慣れてきたら徐々に追加していくやり方が現実的です。

  • E0012(Shared Memory Model 互換性)は対象を絞る: Swoole・RoadRunner・FrankenPHP といった高性能サーバーへの移行を検討している場合、このルールが役立ちます。include_namespacesApp\Service\App\Controller\ など影響を受けやすい名前空間だけを対象にすると、チェックの精度が上がります。

  • テキスト・JSON・SARIF を用途に合わせて使い分ける: 手元での確認はテキスト、スクリプト連携は JSON、GitHub の Code Scanning には SARIF、というように出力形式を場面で切り替えるのがおすすめです。


活用例

  • プルリクエスト単位の品質ゲート: GitHub Actions に phanalist を組み込み、コード変更のたびに自動チェックを実行します。新しい違反が増えた場合はレビューコメントへ自動投稿する仕組みを作れば、レビュアーの負担を減らせます。

  • 技術的負債の見える化: JSON 出力をスクリプトでパース(解析)して Grafana などのダッシュボードツールに蓄積します。複雑度の推移をグラフで追うことで、リファクタリングの効果を数値として確認できます。

  • 新人研修・コーディング規約の形式化: チームのコーディングルールを phanalist のルール設定に落とし込みます。違反が検出されたら「なぜそのルールがあるのか」を学ぶ教材として活用でき、口頭説明だけに頼らない仕組みになります。

  • 既存解析ツールの補完: PHPStan や Psalm ですでに型チェックをしているチームに phanalist を追加し、設計レベルの問題(深いメソッドチェーンや過度に複雑な関数など)を別の視点から検出します。ツールを組み合わせることで検出カバレッジが広がります。

  • 高性能サーバー移行前の事前調査: FrankenPHP や RoadRunner など、PHP をリクエストをまたいでプロセスを使い回すサーバーに移行する前に E0012 ルールで影響箇所を洗い出し、手戻りを減らせます。

  • 個人プロジェクトのセルフレビュー: チームではなく個人でコードを書いている場合も、コミット前に ~/phanalist を走らせるだけでコード品質をサッと確認できます。設定ゼロで動くので導入コストはほぼゼロです。


用語とポイント解説

静的解析(せいてきかいせき) プログラムを実際に動かさず、ソースコードをテキストとして読んで問題を見つける手法です。かんたんに言うと、コードを「目で読んで」バグやくせのある書き方を指摘してくれる仕組みです。実行しなくても検査できるので、テストを書く前の段階でも使えます。

Cyclomatic Complexity(サイクロマティック複雑度) 関数やメソッドの中に「if」「for」「while」などの分岐がいくつあるかを数えて複雑さを数値化した指標です。かんたんに言うと、「この関数はどのくらい入り組んでいるか」を表すスコアです。値が大きいほどテストケースが増え、バグが入り込みやすくなります。phanalist では E0009 というルール番号で管理されています。

NPath Complexity(エヌパス複雑度) 関数を通過しうる実行ルートの総数を計算した指標です。かんたんに言うと、「この関数を全パターン網羅するには何通りのテストが必要か」を示す数値です。Cyclomatic Complexity と組み合わせて使うと、より漏れの少い複雑度把握ができます。phanalist では E0010 に対応しています。

SARIF(サリフ) Static Analysis Results Interchange Format の略で、静的解析の結果を記述するための業界標準 JSON フォーマットです。かんたんに言うと、「解析結果を GitHub や GitLab がそのまま読み込める共通の書き方」のことです。GitHub の Code Scanning 機能はこの形式を直接サポートしています。

Law of Demeter(デメテルの法則) 「直接の知り合いにだけ話しかけなさい」というオブジェクト設計の原則です。かんたんに言うと、$a->getB()->getC()->doSomething() のように何段階もつないで別のオブジェクトを呼び出すのはやめましょう、という考え方です。深い連鎖は変更に弱くなるため、phanalist はこの違反を検出してくれます。

Shared Memory Model(共有メモリモデル) Swoole や RoadRunner のように、PHP のプロセスをリクエストをまたいで再利用するサーバー環境の動作モデルのことです。かんたんに言うと、「一度起動したプログラムをずっと使い回す仕組み」です。この場合、変数が前のリクエストの状態を引き継ぐことがあるため、通常の PHP とは異なる注意が必要です。phanalist の E0012 がその問題を検出します。

バイナリ(実行ファイル) コンパイル済みの実行可能なプログラムファイルのことです。かんたんに言うと、「ダブルクリックやコマンドで直接動かせる完成品のファイル」です。phanalist は Rust でビルドされたバイナリを配布しているため、Rust の開発環境がなくてもすぐ動かせます。

CI/CD(シーアイ・シーディー) Continuous Integration / Continuous Delivery の略で、コードの変更をリポジトリ(ソースコードの置き場)に送るたびに自動でテストやデプロイを実行する仕組みです。かんたんに言うと、「コードを更新したら自動で品質チェックと配信まで流れる自動化ベルトコンベア」のことです。phanalist は終了コードで成否を返せるため、CI 環境にそのまま組み込めます。

サイクロマティック複雑度の閾値(いきち) 「複雑度がこの数値を超えたら警告する」という基準値のことです。かんたんに言うと、「アラームを鳴らすボーダーライン」です。phanalist.yaml で max_complexity を変更することでチームの基準に合わせられます。一般的には 10 前後が目安とされています。


ぜひ CI パイプラインへの組み込みや既存 PHP プロジェクトのリファクタリング調査などに活用してみてはいかがでしょうか。