menu-icon

PHP_CodeSnifferを導入して、git commit時にチェックする

PHP_CodeSnifferを使うと、PHPの記述がコーディング規約に沿ったものであるかを機械的に確認してくれるので、開発者の不注意による規約違反を防ぐことができ、またレビュー時の負担軽減にも繋がります。

今回はPHP_CodeSnifferを導入して、git commit時にチェックが走るような設定を行います。

なお使用した環境は以下の通りです。

  • PHP 7.4
  • Git 2.20

PHP_CodeSniffer

squizlabs/PHP_CodeSniffer

インストール

composerを使ってPHP_CodeSnifferをインストールします。プロジェクトのルートディレクトリで以下を実行します(2021年1月現在は3系が安定版のようです)。

$ composer require --dev squizlabs/php_codesniffer:3.*

インストールできたら、vendor/binphpcsphpcbfという実行ファイルが存在するはずです。

$ ls vendor/bin/    
phpcbf  phpcs

動作確認

実際に規約違反のPHPファイル、Hoge.phpFuga.phpPiyo.php を用意して動作検証してみます。

ディレクトリ構造
/
├ src/
|   └ Models/
|       ├ Fuga.php
|       ├ Hoge.php
|       └ Piyo.php
└ vendor/
src/Models/Hoge.php
<?php

namespace Src\Models;

class Hoge
{
    public function to_string()
    {
        return 'hoge';
    }
}

キャメルケースでないメソッド名が存在しますので、PSR-1: Basic Coding Standardに違反しています。Fuga.phpPiyo.phpもクラス名が違うだけでHoge.phpと同様に違反している状態とします。この状態でphpcsを使ってチェックしてみます。

$ ./vendor/bin/phpcs --standard=PSR12 ./src

FILE: /var/www/html/src/Models/Piyo.php
-----------------------------------------------------------------------
FOUND 1 ERROR AFFECTING 1 LINE
-----------------------------------------------------------------------
 7 | ERROR | Method name "Piyo::to_string" is not in camel caps format
-----------------------------------------------------------------------


FILE: /var/www/html/src/Models/Fuga.php
-----------------------------------------------------------------------
FOUND 1 ERROR AFFECTING 1 LINE
-----------------------------------------------------------------------
 7 | ERROR | Method name "Fuga::to_string" is not in camel caps format
-----------------------------------------------------------------------


FILE: /var/www/html/src/Models/Hoge.php
-----------------------------------------------------------------------
FOUND 1 ERROR AFFECTING 1 LINE
-----------------------------------------------------------------------
 7 | ERROR | Method name "Hoge::to_string" is not in camel caps format
-----------------------------------------------------------------------

Time: 21ms; Memory: 4MB

このように規約違反が検出されました。なお今回はPSR-12: Extended Coding Styleに基づいて検証しています(PSR12)が、使用する規約は--standardオプションによって変更できます(インストールされている規約は-iで確認可能)。

$ ./vendor/bin/phpcs -i    
The installed coding standards are PSR2, MySource, Squiz, PSR12, PEAR, Zend and PSR1

フィルタオプション

今回はgitと連携して使用しますので、--filterオプションで指定できるGitStaged,GitModifiedの各フィルターに関して確認しておきます。それぞれ以下のようなフィルターになります。

  • GitModified … 修正、またはリポジトリに追加したファイルのみを対象とする
  • GitStaged … ステージング状態のファイルのみを対象とする

実際の挙動を見てみます。各ファイルの内容はそのままでソース管理の状態を以下とします。

  • Hoge.php … リポジトリに追加した状態
  • Fuga.php … リポジトリに追加してステージング状態
  • Piyo.php … コミット済み
$ git status -s
A  src/Models/Fuga.php
?? src/Models/Hoge.php

この状態でフィルターを変更して実行してみると、チェック対象が絞りこまれているのがわかります。

フィルタなし
./vendor/bin/phpcs --standard=PSR12 ./src   

FILE: /var/www/html/src/Models/Piyo.php
-----------------------------------------------------------------------
FOUND 1 ERROR AFFECTING 1 LINE
-----------------------------------------------------------------------
 7 | ERROR | Method name "Piyo::to_string" is not in camel caps format
-----------------------------------------------------------------------


FILE: /var/www/html/src/Models/Fuga.php
-----------------------------------------------------------------------
FOUND 1 ERROR AFFECTING 1 LINE
-----------------------------------------------------------------------
 7 | ERROR | Method name "Fuga::to_string" is not in camel caps format
-----------------------------------------------------------------------


FILE: /var/www/html/src/Models/Hoge.php
-----------------------------------------------------------------------
FOUND 1 ERROR AFFECTING 1 LINE
-----------------------------------------------------------------------
 7 | ERROR | Method name "Hoge::to_string" is not in camel caps format
-----------------------------------------------------------------------

Time: 31ms; Memory: 6MB
GitModifiedフィルタ
./vendor/bin/phpcs --standard=PSR12 --filter=GitModified ./src

FILE: /var/www/html/src/Models/Hoge.php
-----------------------------------------------------------------------
FOUND 1 ERROR AFFECTING 1 LINE
-----------------------------------------------------------------------
 7 | ERROR | Method name "Hoge::to_string" is not in camel caps format
-----------------------------------------------------------------------

Time: 64ms; Memory: 6MB
GitStagedフィルタ
./vendor/bin/phpcs --standard=PSR12 --filter=GitStaged ./src

FILE: /var/www/html/src/Models/Fuga.php
-----------------------------------------------------------------------
FOUND 1 ERROR AFFECTING 1 LINE
-----------------------------------------------------------------------
 7 | ERROR | Method name "Fuga::to_string" is not in camel caps format
-----------------------------------------------------------------------

Time: 39ms; Memory: 6MB

Gitの設定

Gitフック

次にGitフックを使ってgit commit時にphpcsが実行されるようにします。

.git/hooksに以下の内容のpre-commitという名前のシェルスクリプトを作成します。

.git/hooks/pre-commit
#!/bin/sh

./vendor/bin/phpcs --standard=PSR12 --filter=GitStaged .

これで設定完了です。

動作確認

先の動作確認時と同様に規約違反のsrc/Models/Fuga.phpがステージング状態とします。コミットを試みるとコミット前にチェックが走り、エラーとなるため、コミットできなくなっていることが確認できます。

$ git status -s
A  src/Models/Fuga.php
?? src/Models/Hoge.php
$ git commit -m "add Fuga Model"

FILE: /var/www/html/src/Models/Fuga.php
----------------------------------------------------------------------
FOUND 1 ERROR AFFECTING 1 LINE
----------------------------------------------------------------------
 7 | ERROR | Method name "Fuga::to_string" is not in camel caps
   |       | format
----------------------------------------------------------------------

Time: 34ms; Memory: 6MB

$ git status -s
A  src/Models/Fuga.php
?? src/Models/Hoge.php

コミットするためには、規約違反を解消しなければなりません。そのため、このpre-commitを開発者全員で共有していれば、規約違反のコードがリポジトリに含まれることは(ほぼ)無くなります。

まとめ

PHP_CodeSnifferを導入して、git commit時にコーディング規約チェックが走るようにしてみました。大抵の場合は今回の設定で事足りるのですが、"(ほぼ)無くなります"と書いているように、実はこの設定だとチェックをすり抜けてしまうことが可能なので、次回もう少し深堀りしてみようと思います。