はじめに
こんにちは、愛知でWEBエンジニアをしているkokuboと申します。
今回はPHPで使用できる静的解析ツールのPHPStanについての投稿です。
初めて参加したPHPカンファレンスでPHPStanを知り、便利なのに無料で導入しやすい点からぜひ業務にも使用したい気持ちから自分なりに記事としてまとめてみました!
簡単に導入しやすいのでまだ使ったことがない方はぜひ使ってみてください!
なぜPHPに「静的解析」が必要なのか?
【PHPの問題点】
PHP は柔軟で書きやすい反面、型や構文の自由度が高く、実行時までエラーが発見されにくいという特徴があります。
【静的解析での問題解決】
プログラムを実行せずにソースコードを分析し、文法エラーや潜在的なバグ、コーディング規約違反などを見つけ出すことができる。PHPに特化した静的解析ツールのことをPHPStanという。
【静的解析で実現できること】
○バグの早期発見:実行前に多くのエラーを潰せる
○コード品質の向上:より堅牢で読みやすいコードになる
○リファクタリングの安心感:変更による影響範囲を把握しやすくなる
○コードレビューの効率化:機械的にチェックできる部分は自動化し、本質的な議論に集中できる
PHPStanとは?
- PHP向けの静的解析ツールとして、現在最も広く使用されているツール
- 拡張機能でLaravelやSymfonyなどフレームワークに特化した解析もできる
- Composerで簡単に導入可能
- Dockerやcurlでもインストール可能
- 解析のレベルを0~9まで設定できる
- 0:基本的な型チェックの身
- 5:実用的な範囲(関数の呼び出しや返り値チェック)
- 8~9:null安全性や未使用コード、複雑な判定も含める
- IDEやCIと統合可能ができる
- よく検出されるエラー例
- 存在しないメソッド呼び出し
- $user->getNmae()(typo)
- プロパティ未定義アクセス
- $product->prce(未定義)
- 型の不一致
- function f(int $x) {} に f("abc")
- nullアクセス
- $obj = null;
- $obj->value;
- 不正なreturn型
- function f(): int { return "abc"; }
- 存在しないメソッド呼び出し
PHPStanのインストール方法
# composerでインストール
composer require --dev phpstan/phpstan
# dockerでインストール
docker run --rm -v $(pwd):/app phpstan/phpstan analyse src
# curlでインストール(ただし、phpstan.pharに実行権限の付与が必要)
curl -L https://github.com/phpstan/phpstan/releases/latest/download/phpstan.phar -o phpstan.phar
実際に使ってみよう!
今回はphpが入っているサーバーであればどこでも使用できる「curlでインストール」した場合の手順で進めます。
- PHPのサーバーに入って(dockerを使用している場合はコンテナに入る)PHPStanのインストール
# 最新のバージョンを使用する場合 curl -L https://github.com/phpstan/phpstan/releases/latest/download/phpstan.phar -o phpstan.phar # 古いPHPバージョンで動作させたいときはバージョンを指定する(例:php7.3) curl -L https://github.com/phpstan/phpstan/releases/download/0.12.99/phpstan.phar -o phpstan.phar
- 取得したファイルに実行権限を付与
chmod +x phpstan.phar
- 何処のディレクトリからでもしようできるように移動
mv phpstan.phar /usr/local/bin/phpstan
- インストールしたPHPStanのバージョンを確認
phpstan --version
- 好きなレベルで解析してみる
# 解析実行コマンド phpstan analyse ディレクトリ --level=5 # 例1)「app」ディレクトリ以下を解析 phpstan analyse app --level=5 # 例2)特定のファイル飲み解析する場合(複数可) phpstan analyse --level=5 app/Http/Controllers/test.php
出力されるログ
生成AIに解析結果のログをいくつか聞いてみました。
どこのファイル、何行目、行数も表示されるので分かりやすいですね!
ありがたや〜😊
Line src/Sample.php
------ -------------------------------------------------------------
9 Parameter #2 $b of method App\Sample::calculate() expects int, string given.
12 Access to an undefined property App\Sample::$undefinedVar.
13 Call to an undefined method App\Sample::undefinedFunction().
6 Parameter $name of method App\Sample::greet() is nullable, but passed to strtoupper() which does not accept null.
------ -------------------------------------------------------------
応用編
- 設定ファイルを使用して細かく制御
ファイル名: phpstan.neon phpstan.neonの中身: parameters: # 解析レベル level: 5 # 解析するディレクトリ paths: - src - app - routes # 解析をしないディレクトリ excludePaths: - tests/* - storage/* - bootstrap/* # 自動読み込み対象のディレクトリ(クラスが定義されているがcomposerで登録されていない場合などに使う) autoload_directories: - tests # 実行時に読み込ませたいファイル。Laravelではブートストラップファイルを指定して依存を解決する autoload_files: - bootstrap/app.php # iterable型の配列などで値の型が明示されていない場合にも警告を出す checkMissingIterableValueType: true # クロージャやコールバック関数のシグネチャが不明な場合に警告を出す checkMissingCallableSignature: true # ジェネリック(例: Collection<int>)のような型が省略された場合に警告を出す checkGenericClassInNonGenericObjectType: true # コンストラクタの中で定義されたprivateプロパティの型を推論するかどうか inferPrivatePropertyTypeFromConstructor: true # ignoreErrors にマッチしないパターンがあると警告を出す(設定ミスの検出) reportUnmatchedIgnoredErrors: true # エラーメッセージの正規表現にマッチするものを無視する ignoreErrors: - '#Call to an undefined method .*#' - '#Access to an undefined property .*#' # 一時ファイルを保存するディレクトリを指定(CIやDockerで便利) tmpDir: /tmp/phpstan # VSCodeと連携してエラー出力をクリックでファイルを開けるようにする editorUrl: 'vscode://file/%file%:%line%'
- エラーの出力をフォーマットする
# JSON phpstan analyse --error-format=json # チェックスタイル(Ciに取り込んで使用) phpstan analyse --error-format=checkstyle > phpstan-report.xml # テーブルで表示 phpstan analyse --error-format=table # GitHub Actionsでエラーをアノテーション(PRなどで便利) phpstan analyse --error-format=github
- gitでの変更内容だけを解析する
git diff --name-only origin/main | grep '\.php$' | xargs phpstan analyse
チーム開発への導入
- GitHub Actionsを使用することでPR時のコードの解析を自動化でき、質の高いコードを保つことができる
- 既存コードがエラーだらけで導入できない場合でも大丈夫!
- 現在のエラーを一旦「無視リスト」として記録することができる
- 新たに追加・修正したコードのエラーだけ検知できる
- 解析レベルを少しづつ上げることで段階的に対応することができる
【GitHub Actionsの使用方法】
・GitHubで管理しているルートディレクトリに「.github/workflows/phpstan.yml」を作成
・以下phpstan.ymlの中身
name: PHPStan
on:
pull_request: # プルリクエスト時にGithub Actionsを実行する
paths:
- '**.php'
- 'phpstan.neon'
- '.github/workflows/phpstan.yml'
jobs:
phpstan:
runs-on: ubuntu-latest # Actionを実行するOS
steps:
#こちらはGithub専用のアクション
- name: Checkout code
uses: actions/checkout@v4
- name: Set up PHP
uses: shivammathur/setup-php@v2
with:
php-version: '7.3' # ← 使用しているPHPバージョン
# PHPStanのインストール
- name: Download PHPStan PHAR
run: |
curl -L https://github.com/phpstan/phpstan/releases/download/0.12.99/phpstan.phar -o phpstan.phar
chmod +x phpstan.phar
# PHPStanの実行
- name: Run PHPStan
run: ./phpstan.phar analyse
まとめ
- とにかく導入が簡単なので一度遊んでみてください!!
- PHPカンファレンスに参加して実に多くの企業が自動化を行なっており、PHPStanを導入している企業も複数いました。私の会社ではあまり自動化が進んでいませんのでこれを機に一歩目として導入していこうと思いました!
最後までご覧いただきありがとうございました☺️