PHP
PHPStan

[PHP] 静的解析ツールPHPStanの機能概要

More than 1 year has passed since last update.


はじめに

PHPのコードを書いているとコンパイルを必要とする言語のように検知できるエラーは動かす前に検知したいと思うことがあると思います。

PHPStanというツールを使えばコンパイラのようなエラーチェックができます。

本記事はPHPStanのversion0.9.2を対象にしています。


PHPStanとはどのようなツールなのか?

PHPStanは、PHPの静的解析ツールです。

PHPStan - PHP Static Analysis Tool

コードを実行せずに


  • 構文エラーはないか?

  • 関数に渡すパラメータの数が適切か?

  • 未定義のものにアクセスしようとしていないか?

  • 関数に渡す値が関数のパラメータの型宣言と一致するか?

  • PHPDocの内容と関数の戻り値は同じか?

などのエラーを見つけてくれます。もちろん他に沢山のチェック項目があります。詳しくは後述の"PHPStanはどういう観点でコードをチェックするのか?"をご覧ください。


必要なPHPVersionは?

PHPStanを実行するにはPHP7.1以上のVersionが必要。(v0.9.2時点)

PHPStanの実行にはPHP7.1以上が必要
ですが、PHPStanで解析する対象のコードはPHP7で書かれたコードでもPHP5時代に書かれたコードでも大丈夫みたいです。

2018-05-08 訂正

PHPStanの作者から指摘をいただきました。

v0.9.2ではPHP7.0以上

v0.10ではPHP7.1以上が必要らしいです。

masterブランチのREADME.mdを参考にしたので間違えてしまいました。tag0.9.2のREADME.mdには7.0になっていました。失礼しました。


インストール方法


スタンダードなインストール方法

Composerでインストールします。


実行コマンド

$ composer require --dev phpstan/phpstan


GitHub phpstan/phpstan Installation 参照。


依存関係がコンフリクトした場合


If you have conflicting dependencies or you want to install PHPStan globally, the best way is via a PHAR archive. You will always find the latest stable PHAR archive below the release notes. You can also use the phpstan/phpstan-shim package to install PHPStan via Composer without the risk of conflicting dependencies.


この場合の最善の方法はPHARアーカイブを使うことみたいです。

また別の方法としてphpstan/phpstan-shimパッケージをComposer経由でインストールする方法も紹介されています。


実行コマンド

$ composer require --dev phpstan/phpstan-shim



その他

Docker経由でも使えるらしいです

phpstan/docker-image


使い方

基本的な使い方は下記のようになります。

analyseコマンドを使用して解析したエラーがなければ下記のように表示され、エラーがあればエラーの内容が表示されます。

$ vendor/bin/phpstan analyse -l 7 path/to/xxx.php

0/1 [>---------------------------] 0%
1/1 [============================] 100%

[OK] No errors

各オプションに関してはhelpを貼り付けましたので下記をご覧ください。


実行コマンド

$ vendor/bin/phpstan analyse -h

Usage:
analyse [options] [--] <paths> (<paths>)...
analyze

Arguments:
paths Paths with source code to run analysis on

Options:
-c, --configuration=CONFIGURATION Path to project configuration file
-l, --level=LEVEL Level of rule options - the higher the stricter
--no-progress Do not show progress bar, only results
--debug Show debug information - which file is analysed, do not catch internal errors
-a, --autoload-file=AUTOLOAD-FILE Project's additional autoload file path
--errorFormat=ERRORFORMAT Format in which to print the result of the analysis [default: "table"]
--memory-limit=MEMORY-LIMIT Memory limit for analysis
-h, --help Display this help message
-q, --quiet Do not output any message
-V, --version Display this application version
--ansi Force ANSI output
--no-ansi Disable ANSI output
-n, --no-interaction Do not ask any interactive question
-v|vv|vvv, --verbose Increase the verbosity of messages: 1 for normal output, 2 for more verbose output and 3 for debug

Help:
Analyses source code



PHPStanはどういう観点でコードをチェックするのか?

現在、次のチェックを実行しています。



  • instanceofcatchtypehintsやannotationなどに記述されたクラスやインターフェースが存在するか?

  • 変数がスコープ内に存在するか?

  • callされたmethodやfunctionは存在しているか?またアクセス権があるか。

  • callされたプロパティやconstは存在しているか?またアクセス権があるか。

  • プロパティに割り当てられた型は正しいか?

  • コンストラクタやメソッドや関数に渡すパラメータの数や型は正しいか?

  • メソッドや関数の返り値は適切な型を返しているか?


  • sprintf,printfに渡す引数の数は正しいか?


  • (string) 'foo'のような無駄なキャストをしていないか?

  • コンストラクタのパラメーターで未使用なものはないか?

  • 親クラスにコンストラクタが定義されている場合はparent::__construct()しているか?

  • 連想配列のkeyには適切な型が使用されているか?(arrayとかobjectはダメよという意味).

  • 連想配列のkeyが重複していないか?

  • foreachに対して適切な値が渡されているか?

  • Classを参照するときは定義したクラス名と大文字小文字まで完全に一致するか?


  • instanceof, ===, !==, is_int(), is_null()などに対して不正な型を使用していないか?

  • phpDocsの検証


  • clone keywordに対してきちんとobjectが渡されているか?

phpstan/phpstan Consider supporting it on Patreon so I'm able to make it even more awesome! 参照

直訳ではありませんが大体あっていると思います。


levelオプションに関して


実行コマンド

$ vendor/bin/phpstan analyse -l 7 path/to/xxx.php


上記のようにlevelオプションが存在します。

現在は0から7までの8段階あり、0がチェックが最も緩く、7がチェックが最も厳しいです。(v0.9.2時点)

古いversionでは段階はもっと少なかったんですけど増えましたね。

phpstan/phpstan Rule levels 参照。

各レベルでどのようなチェックをするのかは

phpstan/confディレクトリにあるneonファイルに記述されているようです。

興味のある方はgithubの該当のディレクトリへのリンクを貼りつけておきますのでご確認ください。

https://github.com/phpstan/phpstan/tree/master/conf

新規に立ち上げるプロジェクトの場合は厳し目で設定しても良いと思います。

しかし、既存のプロジェクトに導入する場合はエラーが多発すると思いますので緩めの設定でスタートして徐々にレベルを上げていく感じになると思います。

適切な設定レベルを探ってください。


phpstan.neonを使用した設定値のカスタマイズ

phpstan.neonというファイルを作成し、パラメータを設定することでphpstanの設定値をカスタマイズできます。(neonファイルって初めて聞きました。。。)


実行コマンド

$ vendor/bin/phpstan analyse -c phpstan.neon -l 7 path/to/xxx.php


phpstan/phpstan Configurationには


  • autoload_directories

  • autoload_files

  • excludes_analyse

  • fileExtensions

  • universalObjectCratesClasses

  • earlyTerminatingMethodCalls

  • ignoreErrors

  • bootstrap

の設定例が記述されています。ここには書かれていませんが、おそらくphpstan/conf/config.neonに書かれているパラメータはphpstan.neonで変更が可能なのだと思います。


config.neonに書かれている設定値

parameters:

bootstrap: null
excludes_analyse: []
autoload_directories: []
autoload_files: []
fileExtensions:
- php
checkAlwaysTrueCheckTypeFunctionCall: false
checkAlwaysTrueInstanceof: false
checkClassCaseSensitivity: false
checkFunctionArgumentTypes: false
checkArgumentsPassedByReference: false
checkMaybeUndefinedVariables: false
checkNullables: false
checkThisOnly: true
checkUnionTypes: false
polluteScopeWithLoopInitialAssignments: true
polluteCatchScopeWithTryAssignments: false
ignoreErrors: []
internalErrorsCountLimit: 50
reportUnmatchedIgnoredErrors: true
universalObjectCratesClasses:
- stdClass
- SimpleXMLElement
earlyTerminatingMethodCalls: []
memoryLimitFile: %tmpDir%/.memory_limit
...



色々書いたけど。。。

メルカリではこのツールを使っているらしいですね。こっちのスライドをみたほうがざっと理解できるかも。

PHPStanで始める継続的静的解析


  • 導入の背景

  • phanではなくPHPStanを選んだ理由

  • PHPStanの注意点

  • CIと組み合わせた活用事例

などがスライドにまとめられています。

2018-05-09 追加

PHPStanで始める継続的静的解析」を発表した時の動画をYouTubeで見つけました。

https://www.youtube.com/watch?v=1RQsHQJCMJ4


おわりに

まだまだ日本語の情報が少ないので英語のドキュメントを翻訳しながら記事を書きました。

英語は得意ではないので解釈が間違っていたらご指摘をお願いします。

また、PHPStanの活用事例があればコメントを頂けると嬉しいです。

ちなみにPHPStanの開発者のblogによると2018年6月に0.10がリリースされるらしいですよ。