PHP
Bash
Git
PHP_CodeSniffer

コーディング規約(PSR-2)を守ったファイルのみcommitしよう

みなさんは普段どういったコーディング規約を採用されていますか?

私は最近までは、1人で開発することがほとんどだったので

  • ハードタブでインデント
  • クラス宣言と同一行にブレースを書く
class Hoge {
}

などと結構自由にやっていましたが、複数人で開発するとなると広く浸透しているPSR-2に慣れた方がいいであろうと思いからPSR-2を徹底しようとしている最中です。

公式のドキュメントとか読んで、だいたい頭に入ったけども正しくかけているか自身がない。。。

EclipseとかIDEを使用していれば、ファイル保存時にPSR-2に準拠するようなフォーマッターを自動で適用するとかできるんですが、Eclipse重いんで最近使っていないです。

まだ慣れていないのでif文の()の前後は半角スペースがいるんだっけ?とかよく迷ってしまいます。
その都度ググって調べるのも正直めんどくさいです。

自動で構文チェックを行おう

php_codesnifferを使用すれば自動で、構文チェック、構文誤りの訂正を行うことが出来ます。
今回は細かくオプションを指定していませんが、独自の規約などにも対応できるようです。詳しく知りたい方はこのあたりをご確認ください。

インストール

今開発しているプロジェクト直下にインストールではなくグローバルでインストールしておいたほうが何かと便利だと思うのでglobalオプションを付けておきます。
あとパスを通すなりalias設定するなりしておくと便利です。

composer global require "squizlabs/php_codesniffer=*"

構文チェック

適当なphpファイル。あえてPSR-2に準拠させてません。

sample.php
<?php
for($i=0;$i<10;$i++){
    echo $i.PHP_EOL;
}
?>

チェック実施。たくさん引っかかりますね。

$ phpcs sample.php --colors --standard=PSR2

FILE: D:\sample.php
----------------------------------------------------------------------------------
FOUND 8 ERRORS AFFECTING 4 LINES
----------------------------------------------------------------------------------
 1 | ERROR | [x] End of line character is invalid; expected "\n" but found "\r\n"
 2 | ERROR | [x] Expected 1 space after FOR keyword; 0 found
 2 | ERROR | [x] Expected 1 space after first semicolon of FOR loop; 0 found
 2 | ERROR | [x] Expected 1 space after second semicolon of FOR loop; 0 found
 2 | ERROR | [x] Expected 1 space after closing parenthesis; found 0
 3 | ERROR | [x] Spaces must be used to indent lines; tabs are not allowed
 5 | ERROR | [x] A closing tag is not permitted at the end of a PHP file
 5 | ERROR | [x] Expected 1 newline at end of file; 0 found
----------------------------------------------------------------------------------
PHPCBF CAN FIX THE 8 MARKED SNIFF VIOLATIONS AUTOMATICALLY
----------------------------------------------------------------------------------

Time: 337ms; Memory: 6Mb

構文誤りの訂正

訂正実施

$ phpcbf sample.php --colors --standard=PSR2

PHPCBF RESULT SUMMARY
----------------------------------------------------------------------
FILE                                                  FIXED  REMAINING
----------------------------------------------------------------------
D:\sample.php                           8      0
----------------------------------------------------------------------
A TOTAL OF 8 ERRORS WERE FIXED IN 1 FILE
----------------------------------------------------------------------

Time: 230ms; Memory: 6Mb

訂正前と後を比較。diffコマンドでは違いが伝わりにくかったのでwinmergeを使って比較した様子の画像を貼っときます。

image_20170906_173508.jpg

これでcommitしようとしているファイルがPSR-2に準拠しているかどうか簡単にチェックできるようになりました。

commit時にphp_codesnifferを自動的に適用させたい

gitには特定のアクションをきっかけにscriptを実行させるという機能があります。
公式ドキュメント

.git/hook/pre-commitというファイルにscriptを書くことで、commitのタイミングで構文チェックを実施、さらに自動で訂正したりcommitを中断させたりも出来ます。

今は自分がどういった書き間違いをしているのか確認したいので、PSR-2に準拠していなければcommitを中断させるようにしています。

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

if git rev-parse --verify HEAD >/dev/null 2>&1
then
    against=HEAD
else
    # Initial commit: diff against an empty tree object
    against=4b825dc642cb6eb9a060e54bf8d69288fbee4904
fi

RETURN=0
# 拡張子がphpのものに対して実施
# 削除したファイル名に対して各コマンドを発行すると、ファイルが見つからないよとエラーになるので削除「D」は除外
for FILE in `git diff --staged --name-only --diff-filter=ACMRTUXB $against | grep "\.php$"`; do
    # シンタックスチェック
    if php -l $FILE>&/dev/null; then
        # 構文エラーが存在しない場合はphp_codesnifferで更にチェック。

        ### 訂正しないでチェックだけの場合はこっち
        # warningはスルー
        phpcs --standard=PSR2 -n $FILE>&/dev/null
        if [ $? != 0 ]; then
            echo "$FILE はPSR2に準拠していません。"
            RETURN=1
        fi
        ### 問題があれば強制的に修正する
        #phpcbf --standard=PSR2 -n $FILE>&/dev/null
        #if [ $? != 0 ]; then
        #    echo "$FILE がPSR2に準拠していなかったので修正しました。"
        #    git add $FILE
        #fi
    else
        echo "$FILEに構文エラーがあります。"
        RETURN=1
    fi
done

exit $RETURN