Laravelプロジェクトの静的解析をLarastanで始める入門

概要

PHP は実行するまでエラーに気づきにくい言語です。タイプミスした変数、存在しないメソッド呼び出し、null が返るのに前提にしていない処理――こうした問題はテストで踏まない限り本番まで届いてしまいます。

静的解析ツール PHPStan は、コードを実行せずにこうした欠陥を検出します。そして Larastan は、その PHPStan を Laravel 向けに強化する拡張です。Eloquent のマジックメソッドやファサードなど「Laravel 特有で静的解析が苦手とする書き方」を理解できるようにしてくれます。

この記事では、既存の Laravel プロジェクトに Larastan を導入し、エラーを少しずつ潰していくところまでを入門として扱います。

環境

  • PHP 8.2 以上
  • Laravel 11 / 12 / 13 系
  • Composer 2 系
  • Larastan 3 系(larastan/larastan)

Larastan のパッケージ名は歴史的に nunomaduro/larastan でしたが、現在は larastan/larastan に移管されています。新規導入では後者を使ってください。

現行の Larastan 3 系は内部で PHPStan 2.x 系を要求します(Larastan 2 系は PHPStan 1.x 系前提でした)。composer require の際は PHPStan の系統が 2.x に揃うことになる点を押さえておいてください。あわせて、Larastan 3 系は Laravel 11.15 以降を対象としているため、Laravel 10 以前のプロジェクトでは 2 系を使うか、先に Laravel 側をアップグレードする必要があります。

発生した問題

静的解析を入れていないプロジェクトでは、次のような問題が「動かしてみるまで」わかりません。

  • 変数名のタイプミス($usr と $user の取り違え)
  • 存在しないメソッド・プロパティへのアクセス
  • nullable な値を非 null 前提で扱っている箇所
  • 型が合わない引数の受け渡し
  • 到達不能コードや無意味な条件分岐

レビューで人力検出するのは限界があり、プロジェクトが大きくなるほど見落としが増えます。

原因

PHP は動的型付けで、しかも Laravel は「書きやすさ」を優先してマジックメソッドを多用します。たとえば次のコードは、素の PHPStan から見ると where も first も「どこに定義されているのか不明」です。

$user = User::where('email', $email)->first();

User モデルに where という静的メソッドは実装されていません。これは __callStatic 経由で Eloquent のクエリビルダに委譲されているためです。素の静的解析ではここで誤検出が大量に出てしまい、実用になりません。

Larastan はこの「Laravel の魔法」を解決するルールと型定義を持ち込むことで、Eloquent・ファサード・コンテナを正しく追跡できるようにします。

対応方法

1. インストール

開発依存としてインストールします。

composer require --dev larastan/larastan

2. 設定ファイルを作る

プロジェクトルートに phpstan.neon(または phpstan.neon.dist)を作成します。

includes:
    - vendor/larastan/larastan/extension.neon

parameters:
    level: 5

    paths:
        - app

    excludePaths:
        - app/Legacy/*

ポイントは includes で Larastan の拡張を読み込むことです。これを忘れると、ただの PHPStan として動作してしまいます。

3. 実行する

./vendor/bin/phpstan analyse

初回はおそらく大量のエラーが出ます。ここで心が折れないことが重要です。後述のレベル調整とベースライン機能で、無理なく始められます。

実装例

レベルは 0 から段階的に上げる

PHPStan には 0(最も緩い)から 10 / max(最も厳しい)までの 11 段階のレベルがあります。最上位の 10 は PHPStan 2.0 で追加されたもので、Larastan 3 系(=PHPStan 2.x 系)なら利用できます。既存プロジェクトにいきなり max を当てると数千件のエラーに埋もれます。

おすすめは level: 0 から始めて、緑になったら 1 ずつ上げる 進め方です。

parameters:
    level: 0

各レベルの大まかな守備範囲は次のとおりです。

レベル 主に検出するもの
0 存在しないクラス・関数・基本的な構文の誤り
1〜2 未定義変数、未知のメソッド・プロパティ
3〜4 戻り値・代入の型の不一致、到達不能コード
5〜6 引数の型チェック、型ヒント不足の検出
7〜8 union 型の部分的な誤り、nullable な値の厳密な扱い
9 明示的な mixed の厳密な扱い
10 暗黙的な mixed(型が書かれていない箇所)の検出

9 と 10 の違いがわかりにくいところですが、9 は「開発者が意図的に書いた mixed」を厳密に扱うのに対し、10 は「型が書かれていないために暗黙的に mixed になっている箇所」まで洗い出します。最初から 10 を狙わず、まずは 5〜6 あたりで型ヒント不足を潰し、そのうえで段階的に引き上げるのが現実的です。

ベースラインで「既存の負債」を凍結する

いきなり全部直すのが難しいときは、現状のエラーをいったん「既知の問題」として退避できます。

./vendor/bin/phpstan analyse --generate-baseline

生成された phpstan-baseline.neon を設定で読み込みます。

includes:
    - vendor/larastan/larastan/extension.neon
    - phpstan-baseline.neon

こうすると 既存のエラーは無視され、新しく増えたエラーだけが検出される ようになります。新規コードから品質を担保しつつ、既存分は余裕があるときに少しずつ減らす、という現実的な運用ができます。

Composer スクリプトに登録する

{
    "scripts": {
        "analyse": "phpstan analyse --memory-limit=1G"
    }
}
composer analyse

解析対象が多いとメモリ不足になりやすいので、--memory-limit を指定しておくと安定します。

PHPDoc で型を補ってヒット率を上げる

/**
 * @return \Illuminate\Database\Eloquent\Collection<int, \App\Models\User>
 */
public function activeUsers(): Collection
{
    return User::where('active', true)->get();
}

情報を与えるほど Larastan の解析精度が上がります。

確認方法

  • ./vendor/bin/phpstan analyse が [OK] No errors を返せば、そのレベルはクリアです
  • レベルを 1 上げて再実行し、増えたエラーを確認します
  • CI に組み込む場合は、終了コードが 0 以外なら失敗する点を利用します

GitHub Actions に組み込む例です。

name: Static Analysis

on: [push, pull_request]

jobs:
  phpstan:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: shivammathur/setup-php@v2
        with:
          php-version: '8.2'
      - run: composer install --no-interaction --prefer-dist
      - run: ./vendor/bin/phpstan analyse --no-progress

これで、解析でエラーが出る PR は CI が赤くなり、マージ前に気づけます。

注意点

  • includes の読み込み忘れ が最頻出のつまずきです。恩恵が出ないときはまずここを疑ってください
  • レベルを上げすぎて大量のエラーに埋もれると続きません。ベースライン+段階的レベル上げ が現実的です
  • 解析対象に vendor やマイグレーション、自動生成ファイルを含めると誤検出やノイズが増えます。paths / excludePaths で絞り込みます
  • メモリ不足は --memory-limit で対処します
  • パッケージ名は新しい larastan/larastan を使います。Larastan 3 系は PHPStan 2.x 系を前提とするため、PHPStan を個別に固定している場合はバージョン整合を確認してください

まとめ

  • Larastan は PHPStan を Laravel 向けに拡張し、Eloquent やファサードの「魔法」を静的解析できるようにするツールです
  • 導入は「composer require --dev → phpstan.neon 作成 → analyse 実行」の3ステップです
  • 既存プロジェクトには レベル 0 から段階的に上げる+ベースラインで負債を凍結 が現実的な始め方です
  • CI に組み込めば、型の崩れや未定義呼び出しをマージ前に検出でき、実行前に多くのバグを潰せます

静的解析は「動かす前にレビュワーがもう一人増える」ようなものです。まずはレベル 0 で緑を出すところから始めてみてください。

\ 最新情報をチェック /

コメントを残す

このサイトはスパムを低減するために Akismet を使っています。コメントデータの処理方法の詳細はこちらをご覧ください。