PHP には、PSR が策定されたおかげで、これをベースにコーディングスタイルがある程度整ってきました。
ここ近年開発がはじまったプロジェクトなら、PSR-1/2 をコーディングスタイルとして採用しているプロジェクトも多いのではないでしょうか。
せっかく採用したなら、実際に書くコードはできるだけこの基準に沿うようにしたいものです。ただ、ここにあまり手間をかけるのも本末転倒です。そこで、手間をかけずに、コーディングスタイルに従えるような方法を模索してみました。
開発環境には、PhpStorm を使う前提です。
PhpStorm の PSR1/PSR2 ルール
まず、PhpStorm の Code Style で、PSR1/PSR2 をルールとして設定しました。
プロジェクト毎に規定したいので、Scheme はProjectにして、set from...をクリックして、Predefined Style から PSR1/PSR2を選択します。

これで、PSR-1/2 のルールがコーディングスタイルへ設定されます。
コーディングスタイルによるコード整形(Reformat)
PHP コードを書いていけば、インデントやブレース位置など自動で適用してくれます。
また、フレームワークで自動生成されたコードなど既存のコードに対して、整形する機能があります。それが Reformat Codeという機能です。
Search Everywhere(⌘ ⌘)から、「reformat」と入力して、選択しても良いですし、⌘ + option + enter でも ok です。
Reformat Codeを実行すると、下記のようなダイアログが表示されます。適用範囲の選択やオプションが選択できます。Optimize importsにチェックを入れておくと不要な import文を削除してくれたりすので、チェックしておくと良いでしょう。Rearrenge entriesにチェックを入れると、メソッドの順序を並べ替えたりするので、これは外しておきます。
Runを実行するとコーディングスタイルに従って、コードが整形されます。

例えば、下記のようなコードがあるとします。
class Foo{
public function hello($show=false) { if($show){print "Hello".PHP_EOL;}
}
}
これを Reformat Code すると、以下のように整形されます。
<?php
class Foo
{
public function hello($show = false)
{
if ($show) {
print "Hello" . PHP_EOL;
}
}
}
Reformat Code は、単一ファイルだけでなく、特定のディレクトリ以下の全てのファイルに対して行うこともできるので、一括で整形するのも簡単です。
PhpStorm PSR1/2 スタイルへの違和感
設定も簡単で良かったのですが、Reformat Code でコード整形すると、これだけは気になるというコードがあります。
それは、クロージャをメソッドの引数に渡すコードです。
例えば、下記のようなコードがあります。
Route::post('/', function() {
return View::make('index');
});
これを Reformat Code すると、下記のようになります。
Route::post(
'/',
function () {
return View::make('index');
}
);
うううん、これは気持ち悪い。。。Reformat する前の方が読みやすいし、行数も少なくて済みます。
コード整形のルールは、Code Styleの設定次第なので、該当箇所を特定して変更していました。
環境毎にいちいち設定?
日頃 iMac と MBA を使って開発しているので、PhpStorm はそれぞれの PC にインストールしています。設定は共有していないので、こうしたカスタマイズを行うと、それぞれに適用する必要があります。
また、PhpStorm は、時折うっかり設定を忘れてしまうようで、たまに再設定を行ったりします。
そして、チームで開発する際は、メンバーがそれぞれ該当箇所を設定するする必要があります。(チームメンバーで設定を共有するような仕組みが PhpStorm にあれば、良いのですが、まあそれは未来に期待して。)
設定自体はそれほど大変ではないですが、全ての環境で行うには手間がかかります。
PHP Coding Standards Fixer
じゃあ、PHP Coding Standards Fixer で、自動変換すれば良いじゃないかと思い、.git/hooks/pre-commitに仕込んだりしたのですが、これもそれぞれの環境で仕込む必要があり、それもまた手間です。
ちなみに、以下のような設定を書いてました。これは自動変換ではなく、コーディングスタイルに合致しないコードがあれば、警告を出して commit を reject する仕様になってます。
#!/bin/sh
#
# An example hook script to verify what is about to be committed.
# Called by "git commit" with no arguments. The hook should
# exit with non-zero status after issuing an appropriate message if
# it wants to stop the commit.
#
# To enable this hook, rename this file to "pre-commit".
#
# php-cs-fixer
#
PROJECTROOT=`echo $(cd ${0%/*}/../../ && pwd -P)`/
FIXER=php-cs-fixer.phar
if [ ! -e ${PROJECTROOT}${FIXER} ]; then
echo "PHP-CS-Fixer not available, downloading to ${PROJECTROOT}${FIXER}..."
curl -s http://cs.sensiolabs.org/get/$FIXER > ${PROJECTROOT}${FIXER}
echo "Done. First time to check the Coding Standards."
echo ""
fi
DIRECTORIES="app bootstrap public package"
for d in ${DIRECTORIES}; do
php ${PROJECTROOT}${FIXER} fix $PROJECTROOT/src/${d} --verbose --dry-run --fixers=indentation,linefeed,trailing_spaces,unused_use,short_tag,visibility,php_closing_tag,braces,extra_empty_lines,include,controls_spaces,elseif,eof_ending,function_declaration
if [ $? -ne 0 ]; then
exit 1
fi
done
もう、PSR1/PSR2 そのままで良いんじゃないか
しばらく悶々としながら開発していたのですが、もう人間の好みは捨てて、ツールに委ねる方が良いのでは、という考えに至りました。
PhpStorm デフォルトの PSR1/PSR2 を適用すれば、かなりの部分は読みやすいコードに整形してくれます。クロージャの部分も読みにくいというより、好みではない(なんとなく気持ち悪い)という程度なので、これは慣れれば、どうということはなさそうです。
結果として、PhpStorm の PSR1/PSR2 をカスタマイズせず、そのままコーディングスタイルとして利用するようになりました。
コーディングスタイルを自動で適用
せっかくのコーディングスタイルですが、毎回、手で Reformat Code を実行するのは手間です。そこで、commit 時に自動で適用するようにしています。
Commit を実行した際に表示されるダイアログの右にある Before Commit の Reformat codeとOptimize importsにチェックを入れておけば、commit 前にこれらを自動実行して、整形済のコードを commit してくれます。
さいごに
本文でも書いたように、現在は、PhpStorm 標準のPSR1/PSR2ルールを利用しており、commit 時に自動で整形されるようにしています。IDE やエディタが複数混在していたり、人数が多くなると、CI などで一括管理した方が良いかもしれませんが、設定の手間と効果を考えると、今のところ、この運用で十分です。
PhpStorm の Reformat Code はなかなか良くできており、多少の好みくらいならカスタマイズせずに、ツールに寄り掛かる方が良いと実感しました。将来フォーマットが変わるかもしれませんが、それはそれで自動整形すれば良いだけです。
これだけツールが良くなると、コーディングスタイルを人間が気にすること自体が無駄な気がしてきて、ツールが勝手に決められたルールに従って整形してくれれば、それで良いという考えになってきました。
ちなみに、件のクロージャのスタイルは時間が経つにしたがって、気にならなくなってきました。引数が多い場面などは、かえってこの方が読みやすいんじゃないかという気さえしてきたので、まあ慣れの問題ですね。


