Table of Contents
ゴール
git commit のフックで自動的に PHPStan を利用した静的解析が実行出来るようになること。
環境
- PHP7.2
 - composer が使える
 
PHPStan とは?
Qiita [PHP] 静的解析ツール PHPStan の機能概要
    PHPStan で始める PHP のための静的解析 #phperkaigi
    基本的な使い方は URL 先やググったら沢山情報がでるのでそちらにお任せしますが、要は静的解析が出来ます。
(PHPMD や PHPlint に近いかな)
ということで導入してみます。
私は毎回コマンドを叩くのが面倒なので git commit にフックさせます。
composer install
composer.json に以下を記述
"require-dev": {
 "phpstan/phpstan": "\*"
 },
 "scripts": {
 "post-install-cmd": [
 "mkdir -p .git/hooks/",
 "cp git-pre-commit .git/hooks/pre-commit",
 "chmod a+x .git/hooks/pre-commit"
],
 }
$ composer install
commit 時にフックさせる
git-pre-commit に以下を記述
PHP\_CODE=$(cat \<\<'EOS'
 $output = array();
 $return = 0;
 exec('git rev-parse --verify HEAD 2\> /dev/null', $output, $return);
 $against = $return == 0 ? 'HEAD' : 'XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX'; // github repoのハッシュ値
 exec("git diff-index --cached --name-only {$against}", $files);
 // 対象ファイルの設定
 $filenamePattern = '/\.(php)$/';
 // 除外ファイルの設定
 $ignorePatterns = [
 '/^bootstrap\/cache\/.\*(php)$/',
];
 $exit\_status = 0;
 foreach ($files as $file) {
 if (!file\_exists($file)) {
 // delete file
 continue;
 }
 if (!preg\_match($filenamePattern, $file)) {
 // don't check files that aren't PHP
 continue;
 }
 foreach ($ignorePatterns as $ignoreFilePattern) {
 // ignore
 if (preg\_match($ignoreFilePattern, $file)) {
 continue 2;
 }
 }
 // PHPSTANを実行する
 ob\_start();
 $stan\_return = [];
 exec(sprintf('./vendor/bin/phpstan analyse --no-progress -l max %s', escapeshellarg($file)), $stan\_return, $stan\_error);
 $output = ob\_get\_clean();
 if ($stan\_error) {
 echo PHP\_EOL, "PHPSTAN error", PHP\_EOL;
 foreach ($stan\_return as $returnK =\> $returnV) {
 echo $returnV, PHP\_EOL;
 }
 $exit\_status = 1;
 continue;
 }
 }
 exit($exit\_status);
 EOS
 )
 php -r "$PHP\_CODE"
 php\_status=$?
 if test $php\_status -ne 0
 then
 echo "git pre-commit hook error"
 echo "please fix the error and retry commit"
 cat \<\<HOGE
 if remove from the index:
 $ git reset
 if edit the file to fix errors and retry commit:
 $ edit FILE\_NAME ...
 $ git add FILE\_NAME
 $ git commit
 HOGE
 exit $php\_status
 fi
コード変更
エラーが出るように変更
\<?php
 namespace App\Http\Controllers;
 use Illuminate\Http\Request;
 use Illuminate\Support\Facades\Hash;
 use App\Models\Member;
 class MembersController extends Controller
 {
 /\*\*
 \* Display a listing of the resource.
 \*
 \* @return \Illuminate\Contracts\View\Factory|\Illuminate\View\Viewaaaaaa // 無い型
 \*/
 public function index()
 {
 $members = Member::all();
 $hoge; // 使用してない変数
 return view('members.index', ['members' =\> $members]); // 型がphpdocsの定義と異なる
 }
 以下省略
git commit
$ git commit -a
------ ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
 Line MembersController.php
 ------ ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
 17 Return typehint of method App\Http\Controllers\MembersController::index() has invalid type Illuminate\View\Viewaaaaaa.
 21 Undefined variable: $hoge
 23 Method App\Http\Controllers\MembersController::index() should return Illuminate\Contracts\View\Factory|Illuminate\View\Viewaaaaaa but returns Illuminate\Contracts\View\Factory|Illuminate\View
 ------ ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
 ↑こんな感じで指摘してくれる
 [ERROR] Found 3 errors
 PHPSTAN error
 git pre-commit hook error
 please fix the error and retry commit
 if remove from the index:
 $ git reset
 if edit the file to fix errors and retry commit:
 $ edit FILE\_NAME ...
 $ git add FILE\_NAME
 $ git commit
良い感じに指摘してくれます。
PHPMD や PHPlint と被るところは多いと思いますが、色々指摘してくれるので便利です。
ただ、これは指摘だけになりますので、PHP-CS-Fixer と絡めて調整してくれるようにすると良いでしょう。
私は、同じ様に git-pre-commit に全部突っ込んでやってます。
指摘は結構でますが、徐々に意識したコードを書くようになります。
新人・経験者に限らず、入れておくと最初は開発のスピードは落ちるでしょうが、そのうちしっかりとしたコードが書けるようになると思います。
おまけ
PHPStan は Laravel で導入すると、やたらめったらエラーを吐きます。
具体的には、routes/web.php などのファイルで Route クラスってどこにあるの?とかです。
何かいい方法が無いかと調べてみたら、PHPStan の Laravel 用があるようです。
GitHub - larastan/larastan: ⚗️ Adds code analysis to Laravel improving developer productivity and code quality.
    
      ⚗️ Adds code analysis to Laravel improving developer productivity and code quality. - larastan/larastan
    
    
  こいつを使えばエラーが出なくなるので便利です。
Laravel ではこっちを使ってみると良いです。
それでは
 hayasaki
主にPHPで業務系のアプリケーションの開発を行っています。