PHPのようなゆるふわな言語を安全に書くためには、コードの綺麗さや作法などを担保する手段が大切になります。 IDEを使う、JenkinsなどのCIサーバーを立ててチェックさせるなどの方法が考えられますが、今回はgitの pre-commit hook を利用して、一定の条件を満たしていないコードはそもそもリポジトリにコミットができないようにしてみました。
できるようになったこと
今回以下の様な事ができるようになりました。
git commit時に、
- コミットされるファイルにシンタックスエラーがあるPHPファイルがる場合、コミットが失敗する。
- コミットされるファイルに作法の悪いコードが有る場合、(使用してない変数があるなど)コミットが失敗する。
- PSRに則ってないファイルが有る場合(改行コードやインデントの統一など)、整形してからコミットする。
これにより、レポジトリ上にコミットされるファイルを制限し、綺麗なファイルだけが存在するという状況を作れます。
以下に実現するためにやったことを書きます。
git の pre-commit hook
gitのリポジトリに、.git/hooks/pre-commit というファイルを作り、実行権限を与えれおくと(忘れがちなので注意)、 git commit時に、コミットが行われる前にそのファイルが実行されます。この時、そのファイルの終了値が1である場合、 その後実行されるはずのコミットはされず、失敗します。くわしくはこちら。
今回これを利用し、コミット時にコミットされるファイルについて検査・整形を行います。
PHPのシンタックスチェック ・・・ php -l
コマンドラインのphpコマンドでlオプションを与えることでシンタックスチェックが出来ます。コマンドラインのphpコマンドがない場合は、インストールします。Ubuntuならaptで入れられます。
$ sudo apt-get install php5-cli
使い方
例えば以下の様なPHPファイルが有る場合、
<?php $i = 0 // セミコロンを忘れてる
次のようにします。
$ php -l test.php PHP Parse error: syntax error, unexpected $end in test.php on line 2 Errors parsing test.php
このように、シンタックスエラーがあるのでそれを教えてくれます。
お行儀のチェック ・・・ phpmd
PHPのコードのお行儀をチェックしてくれる、PHPMDというアプリケーションがあります。 詳しくはサイトを読んで欲しいのですが、例えば使ってない変数を見つける、複雑なループを見つけるなどをしてくれます。
インストール
今回はPEARからインストールしました。サイトに書いてあるとおりにします。
# PEARが入ってない場合 $ sudo apt-get install php-pear $ sudo pear channel-discover pear.phpmd.org $ sudo pear channel-discover pear.pdepend.org $ sudo pear install --alldeps phpmd/PHP_PMD
使い方
例えば以下の様なPHPファイルが有る場合、
<?php class TestClass { private $private; // 使ってないプライベート変数 }
以下の様なコマンドを叩きます。
$ phpmd test.php text unusedcode /home/mana/test_repo/test.php:5 Avoid unused private fields such as '$private'.
このように、privateというプライベート変数を使ってないのでやめましょう、と教えてくれます。 unusedcodeのほかに、codesizeやnamingなどのルールが有ります。詳しくはサイトを読んでください。
SuppressWarnings
また、コードによってはどうしてもルールが適応できないという場合があります。そのような場合は、SuppressWarningsというコメントをつけることで、対象となっているクラスやメソッドをそのルールから除外することができます。
/** @SuppressWarnings("unused") */ class TestClass { private $private; }
ですが、せっかくPHPMDを使用している意味がなくなってしまうので、なるべくなら避けたいところです。
PSR準拠に整形 ・・・ php-cs-fixer
PSRはPHPのコード規約の一つで、 改行コードはLFを使いましょう、インデントはスペース4つにしましょう、クラスの中括弧は次の行に書きましょう、アクセス修飾子は必ず書きましょうといったコードの書き方に関するルールが定められています。 チーム全員がコード規約に則ったコードを書くことで、コードが統一され、プロジェクト全体としてコードが読みやすくなります。
PHPファイルをPSR準拠に整形(ただし、完全ではない)してくれるアプリケーションとして、PHP Coding Standards Fixerがあります。
インストール
サイトに書いてあるとおりにします。
$ sudo wget http://cs.sensiolabs.org/get/php-cs-fixer.phar -O /usr/local/bin/php-cs-fixer $ sudo chmod a+x /usr/local/bin/php-cs-fixer
使い方
例えば、クラスの中括弧が同じ行にある以下の様なPHPファイルが有るとします。
<?php class TestClass { }
これにたいして、次のようにします。
$ php-cs-fixer fix test.php --fixers=braces
すると、PHPファイルが以下のように整形されます。
<?php class TestClass { }
こちらもPHPMDのように様々なルールが有ります。詳しくはサイトを読んでください。 改行コードを統一する linefeed や、インデントをスペース4つに揃える indentation は汎用性が高いと思われます。
pre-commitスクリプト
以上を踏まえて、今回書いたpre-commitスクリプトは以下のようになりました。 これをローカルレポジトリの .git/hooks/pre-commit に配置することで、冒頭で説明したとおりに、コミット時に色々なチェックと整形をしてくれるようになります。
※8/14追記 php-cs-fixerでの修正がその回のコミットに入らなかったので、git addするようにした
#!/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 # Redirect output to stderr. exec 1>&2 IS_ERROR=0 # コミットされるファイルのうち、.phpで終わるもの for FILE in `git diff-index --name-status $against -- | grep -E '^[AUM].*\.php$'| cut -c3-`; do # シンタックスのチェック if php -l $FILE; then # PSR準拠でコード書き換え php-cs-fixer fix $FILE --fixers=linefeed,trailing_spaces,indentation,controls_spaces,eof_ending,php_closing_tag,phpdoc_params,visibility,braces,elseif,include git add $FILE # PHPMDで未使用変数などのチェック if ! phpmd $FILE text unusedcode,codesize,naming; then IS_ERROR=1 fi else IS_ERROR=1 fi done exit $IS_ERROR
あまり厳しすぎると辛いので、PHPMDとphp-cs-fixerのルールについては全ては使っていません。 自分の使いたいルールだけ選べるのはなかなか便利だと思います。
まとめ
gitのpre-commit hookでphp -l、phpmd、php-cs-fixerを呼び出すことで、gitのレポジトリにお行儀の悪いファイルがコミットされることを完全に禁止できます。 特にチーム開発では、全員の環境に導入することで強力なルールとなるため、コードの品質の担保に大きく貢献してくれると思います。