こんにちは、バックエンドエンジニアの三井です。
社内でコードフォーマットを統一する活動を行っており、phpのパッケージを使ったフォーマッターの導入と、git hookを使ったフォーマットの自動化に成功したので概要をまとめていきたいと思います!
導入したphpパッケージ
今回導入したパッケージはphp-cs-fixerです。
導入環境
laravel: 8.60.0
composer: 2.1.6
php: 8.0.9
概要
composer で導入できるphpのパッケージです。導入後コマンドを打つことで任意のファイルにフォーマッターをかけることができます。
フォーマットルールについて、PSR12をはじめ多くのフォーマットに対応しており、設定ファイルを作成することでオリジナルのフォーマットルールを生成することができます。
導入時はPSR12のみを導入して運用してましたが、今後社内でフォーマットを統一するためにルールの取り決めも行っていきたいと思っております!
導入方法・設定
インストール
今回は私の動作環境であるlaravelプロジェクト内での使用を想定して行います。
# パッケージのインストール composer require friendsofphp/php-cs-fixer # 設定ファイルをプロジェクトディレクトリに追加 touch .php-cs-fixer.dist.php # gitignoreにキャッシュファイルを追加 .php-cs-fixer.cache
設定ファイル
設定ファイル.php-cs-fixer.dist.php
内を以下のように記述します。
ルールはここで確認することができ、PSR12
等複数のルールをまとめたルールセットを指定することも可能です。
<?php /* * This document has been generated with * https://mlocati.github.io/php-cs-fixer-configurator/#version:3.1.0|configurator * you can change this configuration by importing this file. */ $config = new PhpCsFixer\Config(); return $config ->setRiskyAllowed(true) ->setRules([ '@PSR12' => true, // ここにルール追記 ]) ->setFinder(PhpCsFixer\Finder::create() ->exclude([ // 除外ファイル 'vendor' ]) ->in(__DIR__) ) ;
setRiskyAllowed()
: riskyなルール(コードを書き換える破壊的な修正を含むルール)を有効にするかを設定します。
setRules()
: 使用したいルールをここで列挙します。
setFinder()...->exclude([''])
: 除外したいディレクトリ名を列挙することでそのディレクトリ内のファイルは無視されます。
ルール設定方法
ルール生成用のツールで生成ファイルを作ることができます。
https://mlocati.github.io/php-cs-fixer-configurator/#version:3.1
このページでは使用可能なルールが列挙されており、ページ内の歯車マークをクリックすると使用するルールの選別ができるようになります。
またその状態で+
ボタンを押すことでルールセットの指定も可能です。
最後にExport
ボタンを押すことで設定ファイルの出力ができます。
実行コマンド
# version バージョン確認 $ ./vendor/bin/php-cs-fixer --version # dry-run (修正はされないが、--diffオプションで修正前後の確認ができる) $ ./vendor/bin/php-cs-fixer fix -v --diff --dry-run # fix 実際に修正実行 $ ./vendor/bin/php-cs-fixer fix -v --diff
--dry-run # 変更なし実行 --diff # 差分出力 --allow-risky # riskyルールの許可
git hookの概要
詳しい説明は割愛しますが簡単に説明すると、gitのコミット等のコマンドの直前・後にスクリプトを実行できるという仕組みです。
今回は"コミット直前にフォーマッターを実行し、修正後コミットする"という機構を作ります。
隠しディレクトリ.gitの配下にhooks
ディレクトリを作りpre-commit
ファイルを作成します。
#!/usr/bin/env bash #ルートの設定(laravel projectの配下を指定) ROOT=$(git rev-parse --show-toplevel)/projdir PHP_CS_FIXER="./vendor/bin/php-cs-fixer" HAS_PHP_CS_FIXER=false if [ -x $ROOT/vendor/bin/php-cs-fixer ]; then # パッケージの存在チェック HAS_PHP_CS_FIXER=true fi LIST=$(git status | grep -e '\(modified:\|new file:\)'| grep '\.php' | cut -d':' -f2) if $HAS_PHP_CS_FIXER; then ERRCNT=0 for file in $LIST do # --dry-runオプションで先にエラーチェック ./projdir/vendor/bin/php-cs-fixer fix $file --diff --dry-run --path-mode=intersection --config=$ROOT/.php-cs-fixer.dist.php >/dev/null 2>&1; ERR=$? # ステータスコードが0(修正なし)か8(修正あり)以外はエラーに該当するのでエラーメッセージを表示 if [ $ERR != 0 -a $ERR != 8 ]; then ERRCNT=$((ERRCNT+1)) echo "php-cs-fixer-$ERR エラーが検出されました $file" echo "error $ERRCNT" else # 修正実行 ./projdir/vendor/bin/php-cs-fixer fix $file --path-mode=intersection --config=$ROOT/.php-cs-fixer.dist.php >/dev/null 2>&1; git add "$file"; fi done if [ $ERRCNT -gt 0 ]; then echo "php-cs-fixer $ERRCNT 件エラーが検出されました" exit 1 fi echo "php-cs-fixer フォーマット修正が完了しました" else echo "" echo "Please install php-cs-fixer, e.g.:" echo "" echo "composer require --dev fabpot/php-cs-fixer:dev-master" echo "" exit 1 fi
これでcommit時にこのスクリプトが自動実行され、フォーマッターが動きます。
実際に開発で運用してみた感想
今回フォーマッターの統一に至った経緯としては社内で使用エディタが統一されていなかったため、各々のフォーマットでコーディングされていたという状況を受けてのことでした。
実際に使ってみて思ったこととしては、エディタ内のフォーマッターと合わせて運用すると良いかもしれない、ということです。コミット直前に修正を行うデメリットとして、コードを書いている途中で整ったコードを見れないという点です。commit内容としては整っているコードですが、"実装中にコードを読みやすくする"にすることが目的なら本末転倒だと思います。そのため、"自分がわかりやすいように"エディタのフォーマッターも兼ねて運用するのも有効だと思いました。