【テクニカル・上級編】PhpStormの「Search Structurally」で作る自動レビューツール:独自のコーディング規約を自動チェック – 総合開発環境(IDE)生産性向上バイブル

PhpStorm Structural Search & Inspect 徹底攻略:チーム開発の自律的秩序を生み出す「ガードレール」の構築法

数多のCI/CDパイプラインを構築し、数千に及ぶプルリクエストのレビュー地獄をくぐり抜けてきたアーキテクトなら、誰もが痛感している真理がある。
「人間の目によるコードレビューは、スケールしない」

どれほどシニアなエンジニアを揃えようとも、レビュー時の疲労、属人的な知識の差、そして「これ、前にも指摘したよな」という心理的摩擦は、組織のベロシティを確実に殺していく。静的解析ツール(PHPStanやPsalm、ESLint等)は強力だが、プロジェクト固有のドメイン知識や、「うちのチームではこのレガシーなトレイトのメソッドではなく、こちらの新ファサードを使わなければならない」といった文脈依存の規約を検出するには、設定の複雑さという高い壁が存在する。

JetBrains PhpStormに隠された「Structural Search and Replace (SSR:構造的検索と置換)」。これは単なる正規表現の化け物ではない。コードの抽象構文木(AST:Abstract Syntax Tree)を直接走査し、ノードの構造や型、変数名をパターンマッチングさせる、開発環境内蔵の最強のクエリエンジンだ。

今回は、このSSRを単発の検索ツールとして終わらせず、IDEのインスペクション(リアルタイム警告)に統合し、さらにはヘッドレスモードでCI/CDパイプラインの防壁として機能させる「コードのガードレール」の全実装術を授ける。

—

1. 内部アーキテクチャ:なぜ「正規表現」ではなく「AST」でなければならないのか

一般的なテキストベースの検索は、空白や改行、コードフォーマットの揺れに極めて弱い。また、「特定のメソッドが、特定の引数の組み合わせ、あるいは特定の文脈(例:トランザクション内)でのみ呼ばれているか」といった文脈を判定することは、正規表現では不可能に近い。

PhpStormのSSRは、JetBrainsが誇る言語パーサーがコードを解析して生成したAST(抽象構文木)をターゲットにする。

[ PHP Source Code ]
↓ (Lexer / Parser)
[ AST (抽象構文木) ] <--- PhpStorm SSR Engine が直接走査 ↓ [ パターンマッチング (変数、型、修飾子) ] このアーキテクチャにより、以下の圧倒的なアドバンテージがもたらされる。

  • 空白・改行・フォーマットの完全な無視: コードがどのように整形されていあようと、構造が一致すれば一網打尽に検出できる。
  • 型やモディファイアの厳密な制約: 「特定のインターフェースを実装したクラスのインスタンス」といった、セマンティック(意味論)な条件指定が可能。
  • プレースホルダーによる柔軟な抽出: `$Var$` や `$Method$` のようなワイルドカードを定義し、マッチしたパーツを置換や警告メッセージに動的に埋め込める。

—

2. 実践:独自のカスタムインスペクションの作成手順

プロジェクトに新しく参入したメンバーが、絶対に書いてはならないアンチパターンを叩くための「ガードレール」を実際に構築する。

シナリオ:レガシーな直接DBクエリ(`DB::statement`)の駆逐と、リポジトリ層の強制

チームでは、生SQLを直接実行する `DB::statement()` や `DB::select()` をドメイン層やコントローラー層に直接書くことを禁止し、専用のRepositoryクラスを経由するという規約があるとしよう。これをリアルタイムで検知し、エディタ上で赤波線(Error)を出力させる。

ステップ1: SSRパターンの定義

1. PhpStormで `Ctrl + Shift + F` (macOSは `Cmd + Shift + F`)を押し、検索モーダルを開く。
2. 「Tools」> 「Find Structurally using Pattern…」 を選択。
3. 以下のテンプレートを入力する。

// 検索パターン (Search template)
DB::statement($query$);

4. `$query$` 部分をクリックし、右側の「Edit Variables」から制約(Constraints)を設定する。

  • これにより、特定の文字列リテラルのみを対象にする、あるいは変数のみを対象にするなどの制御が可能になる。今回はデフォルトのままで「任意の式」にマッチさせる。

ステップ2: インスペクション(Inspection)への昇格

この検索クエリを、一時的なものにせず、プロジェクト全体の常時監視ルール(インスペクション)として登録する。

1. 検索ダイアログの右上にある 「Saveとしてのアイコン(Save Template)」 をクリックし、名前を `Prohibit raw DB::statement` として保存する。
2. 設定画面を開く (`Ctrl + Alt + S` / `Cmd + ,`)。
3. 「Editor」 > 「Inspections」 に移動し、検索窓に `Structural search` と入力する。
4. 「PHP」カテゴリ(またはプロジェクトの言語カテゴリ)の下にある 「Structural search」 を探してチェックを入れる。
5. リストの下部にあるカスタムテンプレート一覧から、先ほど保存した `Prohibit raw DB::statement` を選択する。
6. 重大度(Severity)を 「Error」 に設定し、メッセージを記述する。

  • メッセージ例: `ドメイン層およびコントローラー層での生SQL実行は禁止されています。Repositoryクラスを注入してください。`

これで、開発者がコードを書いた瞬間に、IDEがASTレベルでこのパターンを検出し、ビルドやテストを回す前段階でエラーとして弾き返す体制が整う。

—

3. チーム共有: `.idea` ディレクトリを通じたインスペクション設定のバージョン管理

個人のマシーンで設定が完結していては、DevOpsの理念に反する。チーム全員が全く同じガードレールを共有するためには、PhpStormの設定をコードとしてバージョン管理する必要がある。

PhpStormはプロジェクト設定を `.idea` ディレクトリ内のXMLファイル群として保持している。カスタムSSRインスペクションは `.idea/inspectionProfiles` 配下に保存される。

共有プロファイルの構成管理

カスタムインスペクションをチーム標準として強制するには、以下の手順で `.idea` 内のファイルをGitに含める。

1. 設定画面 (`Editor > Inspections`) で、現在のプロファイルを「Project Default」にするか、あるいは独自の名称(例: `Company_Strict_Standard.xml`)でエクスポートする。
2. 以下の構造のファイルが生成されていることを確認する。


3. このファイルをGitの管理下に置く (`git add .idea/inspectionProfiles/Company_Strict_Standard.xml`)。
4. チームメンバーがリポジトリをクローンし、PhpStormで開くと、自動的にこのインスペクションルールが同期され、全員の環境で同一のガードレールが稼働する。

—

4. CI/CDパイプラインとの高度な統合:ヘッドレスInspection

「IDEが入っていないCI環境(GitHub Actions, GitLab CI等)で、どうやってこのSSRインスペクションを走らせるのか?」
ここが本記事のハイライトの一つである。JetBrainsは、CI環境向けにIDEのコアエンジンをヘッドレス(GUIなし)で実行する 「Qodana(コダナ)」、あるいは 「PhpStorm Command-line Inspector (inspect.sh)」 を提供している。

ここでは、最も軽量かつ確実な Qodana CLI を用いて、GitHub Actions上でSSRを含むすべてのインスペクションを完全に自動実行し、規約違反がある場合にビルドを落とするパイプラインを構築する。

GitHub Actionsワークフローの設定 (`.github/workflows/qodana.yml`)

name: Qodana Code Quality Guardrail

on:
pull_request:
branches: [ main, develop ]
push:
branches: [ main, develop ]

jobs:
qodana:
name: Headless PhpStorm Inspection & SSR Check
runs-on: ubuntu-latest
permissions:
contents: write
pull-requests: write
checks: write

steps:
# リポジトリのチェックアウト(.ideaの設定も含めて取得)

  • name: Checkout Code

uses: actions/checkout@v4
with:
fetch-depth: 0

# Qodana (PhpStormベースの静的解析エンジン) の実行

  • name: ‘Qodana Scan’

uses: JetBrains/qodana-action@v2023.3
env:
QODANA_TOKEN: ${{ secrets.QODANA_TOKEN }} # JetBrains Cloud連携用(ローカル完結ならなくても可)
with:
args: –profile-name,Company_Strict_Standard # IDEで作成・共有したプロファイルを指定

# 検出された問題のPRへのコメント自動化やレポート保存

  • name: Upload Qodana SARIF Report

uses: github/codeql-action/upload-sarif@v3
if: always()
with:
sarif_file: ${{ runner.temp }}/qodana/results/qodana.sarif.json

このパイプラインが走ることで、開発者がどんなに巧みにコードを書いても、`.idea/inspectionProfiles/Company_Strict_Standard.xml` に定義されたStructural Searchのパターンに引っかかった瞬間、GitHubのプルリクエスト上で容赦なくブロックされる。人間がコードレビューで「ここ、直接DB::statement使ってますよ」と指摘する手間は、完全に消滅するのだ。

—

5. パフォーマンス最適化と大規模コードベースにおけるハック

数百万行を超えるモノリスなPHPコードベースにおいて、複雑なASTパターンマッチングをリアルタイム(エディタ入力中)やCIで実行すると、CPUスパイクやメモリ枯渇(OOM)を引き起こすリスクがある。DevOpsリードとして、パフォーマンスチューニングのノウハウを共有しておこう。

1. インスペクションスコープの限定 (Inspection Scopes)

プロジェクト全体を常時スキャンさせる必要はない。例えば、テストコードやベンダーコード、自動生成されたマイグレーションファイルに対して、ドメイン駆動設計(DDD)用の厳格なSSRを走らせるのは無駄なリソース消費である。

  • 対策: PhpStormの「Scopes」機能を用い、インスペクションの適用範囲を `src/Domain` や `src/Application` に限定する。
  • `.idea/scopes/` 配下のXML設定を調整し、CI実行時もスキャン対象を絞り込むことで、解析時間を最大70%削減できる。

2. メモリ割り当ての最適化 (`phpstorm.vmoptions`)

ローカル環境で多数の複雑なSSRインスペクションを有効にしている場合、PhpStormのデフォルトヒープサイズではガベージコレクションが頻発し、タイピング遅延(Input Lag)を招く。

  • `Help > Edit Custom VM Options` から、以下の設定を推奨値に引き上げる。

ヒープサイズの最大値を4GBに拡張(大規模モノリス向け)
-Xmx4096m

予約メモリサイズ
-Xms1024m

厳格なASTツールの効率化のためのガベージコレクタ指定
-XX:+UseG1GC
-XX:CICompilerCount=4

—

6. さらなる高みへ:複雑なSSRパターンの実例集

最後に、現場で即座に使える高度なSSRパターンのレシピをいくつか提示する。これをテンプレートとしてインポートし、自社の規約に合わせてカスタマイズしてほしい。

レシピ A: `dd()` や `dump()` のプロダクションコード混入防止

デバッグ用の関数がコミットに含まれていないかを検知する。

  • Search template:

dd($x$);

  • 別パターン (複数引数対応):

dump($x$, $y$);

  • 制約: なし(無条件でエラーにする)

レシピ B: 非推奨のグローバルヘルパー関数の検出

例えば、特定のレガシーヘルパー関数(例: `old_encrypt()`)の代わりに、新しいDIサービスを使うよう強制する場合。

  • Search template:

old_encrypt($data$);

  • Replace template (一括置換用):

app(\App\Services\CryptoService::class)->encrypt($data$);

  • 解説: SSRは検索だけでなく「置換(Replace)」もASTベースで行えるため、数千箇所にある古い関数呼び出しを、引数の構造を維持したまま一瞬でセキュアな新サービス呼び出しにリファクタリングできる。正規表現では引数のネストや改行を考慮すると破綻するが、ASTなら完璧に安全に置換を完了する。

—

結び:規約を「文書」から「コード」へ

「コーディング規約はWikiに書くな、コードに書け(そしてツールに強制させろ)」
これが、数々の修羅場を潜り抜けてきたDevOpsアーキテクトとしての結論だ。

PDFやMarkdownで書かれた分厚いコーディング規約は、誰にも読まれず、レビューのたびに水掛け論を生むだけの「負の遺産」になりがちだ。しかし、PhpStormの Structural Search を活用し、それを `.idea` でリポジトリ管理し、さらに Qodana や Headless Inspector を通じて CI/CD の防壁に組み込むことで、「規約違反のコードは、物理的にコミットすらできない世界」が完成する。

人間は、より創造的なアーキテクチャの設計や、ビジネス価値の創出に集中すべきだ。機械にできることは機械に徹底的にやらせる。そのための最強の武器が、このPhpStormのSSRなのだ。今すぐプロジェクトに独自のガードレールを実装し、チームのコード品質を次の次元へと引き上げてほしい。

タイトルとURLをコピーしました