PHP-CS-FixerはコマンドひとつでPHPコードを美しく整形してくれる魔法のような開発ツールだ。ソースコードのスタイルがおかしなところを指摘するだけでなく訂正までしてくれる。いわばソースコードの「赤ペン先生」だ。
特に複数人が携わる開発現場では、PHP-CS-Fixerを取り入れることで、各自のコーディングの癖を取り除き、コーディングスタイルが統一され、コードの保守性向上が期待できる。
PHP-CS-Fixerのデモ
こういうやる気のないコードでも……
<?php
use UnusedImportedClass;
class A {
/**
* 適当なDocComment
*/
private function hoge(int $x, int $y){}
private $arr = array(1,2,3,);
/**
* @param int $a
* @param string $bar
*/
function hoge( $a, $bar ) {
if ($a === 1) {
# 特殊なケース
return $bar;
} else {
//
return $bar.$bar;
}
}
}
PHP-CS-Fixerにかかると、美しくなる!
<?php
declare(strict_types=1);
class A
{
private $arr = [1, 2, 3];
/**
* @param int $a
* @param string $bar
*/
public function hoge($a, $bar)
{
if ($a === 1) {
// 特殊なケース
return $bar;
}
return $bar . $bar;
}
/**
* 適当なDocComment.
* @param int $x
* @param int $y
*/
private function hoge(int $x, int $y): void
{
}
}
コードレビュー(人力)によるコード整形との比較
コードレビュー(人力) | PHP-CS-Fixer |
---|---|
手間がかかる | すぐ終わる |
お互い気を使う | 相手が機械だから気兼ねない |
IDEの自動整形機能との比較
IDEの整形機能 | PHP-CS-Fixer |
---|---|
コードの自動整形ができる | コードの自動整形ができる |
スニペット単位の整形が可能 | ファイル単位が整形の最小単位 |
個人的な整形に向いている | チームで整形に取り組める |
整形ルールを共有しにくい | 整形ルールをGitに入れておける |
みんなで同じIDEを使わないといけない | 開発者のエディタに制約がない |
CIでは使いにくい | CIでも使いやすい |
PhpStormは有料 | 無料、有料ライセンス不要 |
PHP-CS-Fixerをインストールする
composer.jsonがあるディレクトリにて、composerコマンドでphp-cs-fixerをインストールする。
composer require --dev friendsofphp/php-cs-fixer
インストールできたか確認する。
❯ ./vendor/bin/php-cs-fixer --version
PHP CS Fixer 2.9.0 Speechless by Fabien Potencier and Dariusz Ruminski
整形予定を確認する
さっそくフォーマットしてもいいが、その前にどう変わるか見ておこう。
❯ ./vendor/bin/php-cs-fixer fix --dry-run ./src
Loaded config default.
Using cache file ".php_cs.cache".
1) src//Json.php
2) src//Json/EncodingContext.php
3) src//Json/DecodingException.php
4) src//Json/Encoder.php
5) src//Json/DecodingContext.php
6) src//Json/EncodingException.php
7) src//Json/Decoder.php
Checked all files in 0.725 seconds, 10.000 MB memory used
php-cs-fixer fix $変更対象のディレクトリ
のコマンドに--dry-run
オプションを付けると整形無しに変更予定のファイル一覧を見ることができる。この例では、7つのファイルが変更予定だ。
次にどんな整形予定か差分を確認しよう。--dry-run
オプションに加えて--diff
を加える。更にお好みで差分の表示形式指定--diff-format udiff
を加えても良い。
./vendor/bin/php-cs-fixer fix --dry-run --diff --diff-format udiff ./src
次が差分の出力例だ。赤色が消されるコード。緑色が足されるコードだ。次例では有るべきでない改行を取り除くことを意味している。
整形を実行する
整形予定が確認できたら整形を実行する。
./vendor/bin/php-cs-fixer fix ./src
もし変更前のコードがGit管理下にあるなら、PHP-CS-Fixerが加えた変更をgit
コマンドで確認できるだろう。
❯ git status -s
M composer.json
M src/Json.php
M src/Json/Decoder.php
M src/Json/DecodingContext.php
M src/Json/DecodingException.php
M src/Json/Encoder.php
M src/Json/EncodingContext.php
M src/Json/EncodingException.php
整形設定ファイル .php_cs.dist を作る
PHP-CS-Fixerは設定なくともよしなに整形してくれるが、整形方法を細かくカスタマイズすることもできる。整形設定を好みのものにするには、まず.php_cs.dist
という名前で整形ルール設定ファイルを作る。このファイルはGitにコミットし、プロジェクトチームで共有する。
touch .php_cs.dist
ちなみに、.php_cs.distと.php_csの2つのファイルが有ると、.php_csが優先して読み込まれる。.php_cs.distはチーム共有のもの、.php_csは開発者個人のものという位置づけだ。.php_csは.gitignoreでGitにコミットされないようにしておく。
.php_cs.distの設定は次のように書く。ちなみに下記と同等の「PHP-CS-Fixerの設定が面倒くさい人のためのルールセット - Qiita」もあるのでご参考に。
<?php
return PhpCsFixer\Config::create()
->setRiskyAllowed(true)
->setRules([
'@PSR2' => true,
'align_multiline_comment' => true,
'array_syntax' => ['syntax' => 'short'],
'binary_operator_spaces' => true,
'blank_line_after_opening_tag' => true,
'blank_line_before_statement' => ['statements' => ['declare', 'do', 'for', 'foreach', 'if', 'switch', 'try']],
'cast_spaces' => true,
'class_attributes_separation' => true,
'combine_consecutive_issets' => true,
'combine_consecutive_unsets' => true,
'compact_nullable_typehint' => true,
'concat_space' => ['spacing' => 'one'],
'declare_equal_normalize' => true,
'declare_strict_types' => true,
'dir_constant' => true,
'ereg_to_preg' => true,
'escape_implicit_backslashes' => true,
'explicit_indirect_variable' => true,
'explicit_string_variable' => true,
'final_internal_class' => true,
'function_to_constant' => true,
'function_typehint_space' => true,
'general_phpdoc_annotation_remove' => ['annotations' => ['class', 'package', 'author']],
'hash_to_slash_comment' => true,
'heredoc_to_nowdoc' => true,
'include' => true,
'is_null' => ['use_yoda_style' => false],
'linebreak_after_opening_tag' => true,
'list_syntax' => true,
'lowercase_cast' => true,
'magic_constant_casing' => true,
'method_chaining_indentation' => true,
'method_separation' => true,
'modernize_types_casting' => true,
'native_function_casing' => true,
'no_alias_functions' => true,
'no_blank_lines_after_class_opening' => true,
'no_blank_lines_after_phpdoc' => true,
'no_empty_comment' => true,
'no_empty_phpdoc' => true,
'no_empty_statement' => true,
'no_extra_consecutive_blank_lines' => ['tokens' => ['break', 'continue', 'extra', 'return', 'throw', 'use', 'parenthesis_brace_block', 'square_brace_block', 'curly_brace_block']],
'no_homoglyph_names' => true,
'no_leading_import_slash' => true,
'no_leading_namespace_whitespace' => true,
'no_mixed_echo_print' => true,
'no_multiline_whitespace_around_double_arrow' => true,
'no_multiline_whitespace_before_semicolons' => true,
'no_null_property_initialization' => true,
'no_php4_constructor' => true,
'no_short_bool_cast' => true,
'no_singleline_whitespace_before_semicolons' => true,
'no_spaces_around_offset' => true,
'no_trailing_comma_in_list_call' => true,
'no_trailing_comma_in_singleline_array' => true,
'no_unneeded_control_parentheses' => true,
'no_unneeded_curly_braces' => true,
'no_unneeded_final_method' => true,
'no_unreachable_default_argument_value' => true,
'no_unused_imports' => true,
'no_useless_else' => true,
'no_useless_return' => true,
'no_whitespace_before_comma_in_array' => true,
'no_whitespace_in_blank_line' => true,
'normalize_index_brace' => true,
'object_operator_without_whitespace' => true,
'ordered_class_elements' => true,
'ordered_imports' => true,
'php_unit_construct' => true,
'php_unit_dedicate_assert' => true,
'php_unit_mock' => true,
'php_unit_namespaced' => true,
'phpdoc_add_missing_param_annotation' => ['only_untyped' => false],
'phpdoc_align' => ['tags' => ['param']],
'phpdoc_annotation_without_dot' => true,
'phpdoc_indent' => true,
'phpdoc_inline_tag' => true,
'phpdoc_no_access' => true,
'phpdoc_no_empty_return' => true,
'phpdoc_no_package' => true,
'phpdoc_order' => true,
'phpdoc_return_self_reference' => true,
'phpdoc_scalar' => true,
'phpdoc_single_line_var_spacing' => true,
'phpdoc_summary' => true,
'phpdoc_to_comment' => true,
'phpdoc_trim' => true,
'phpdoc_types' => true,
'phpdoc_types_order' => true,
'phpdoc_var_without_name' => true,
'pow_to_exponentiation' => true,
'protected_to_private' => true,
'random_api_migration' => true,
'return_type_declaration' => true,
'self_accessor' => true,
'semicolon_after_instruction' => true,
'short_scalar_cast' => true,
'simplified_null_return' => true,
'single_blank_line_before_namespace' => true,
'single_line_comment_style' => true,
'single_quote' => true,
'space_after_semicolon' => ['remove_in_empty_for_expressions' => true],
'standardize_not_equals' => true,
'ternary_operator_spaces' => true,
'ternary_to_null_coalescing' => true,
'trailing_comma_in_multiline_array' => true,
'trim_array_spaces' => true,
'unary_operator_spaces' => true,
'void_return' => true,
'whitespace_after_comma_in_array' => true,
'yoda_style' => ['equal' => false, 'identical' => false],
])
->setFinder(PhpCsFixer\Finder::create()
->exclude('vendor')
->in(__DIR__)
)
;
効率的に設定を書くコツ
PHP-CS-Fixerの整形ルールは数十ある。ひとつひとつ精査していると丸一日がかりの作業になる。効率的に設定を書くには次を注意しよう。
完璧を目指しすぎない
プロジェクトに携わる皆で揺れの少ないコードを書くことが目的ならば、ルールの詳細にこだわらず、まずは自動整形できる環境を作ること優先しよう。ルールは後からでも変えられる。
迷ったらデフォルトで
ルールの選択で5秒考えて迷ったらひとまずデフォルトにしておこう。PHP-CS-Fixerのデフォルト値は標準的なコーディング規約に従っていたり、より一般的なものが選択されているので、デフォルトでも全く問題はない。
ルールの詳細はdescribe
コマンドで確認しよう
ルールの詳細はdescribe
コマンドで確認できるので、よく分からないものはそれを見ながら設定すると良い。整形前のコードと整形後のコードまで示してくれる親切設計だ。
php-cs-fixer describe array_syntax
PHP-CS-Fixer Configuratorを活用しよう
設定を画面でポチポチやっていきたい場合はPHP-CS-Fixer Configuratorが便利。加えたいルールプリセットやルールを選んでいくと設定ファイルを書き出してくれる。
最後までお読みくださりありがとうございました。Twitterでは、Qiitaに書かない技術ネタなどもツイートしているので、よかったらフォローお願いします→Twitter@suin