はじめに
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で書かれたコードでもPHP5時代に書かれたコードでも大丈夫みたいです。
PHPStanの実行にはPHP7.1以上が必要
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
2019-12-20 訂正
@tadsan にコメントでご指摘をいただきましたようにphpstan/phpstan-shim
はアップデートされなくなります。
本記事はversion0.9.2の時に書いた記事ですので、phpstanの最新のreadmeをご覧ください。
その他
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はどういう観点でコードをチェックするのか?
現在、次のチェックを実行しています。
-
instanceof
やcatch
やtypehints
や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で変更が可能なのだと思います。
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がリリースされるらしいですよ。