なんでやるの?
コードを静的解析させることにより開発者の書き方のクセをなくす。
コードレビューの時に正しく動いててもフォーマット通りの書き方じゃないと
見てて違和感感じますよね?汗
書いてるうちに無意識に宣言していたキャメルケースでない変数とかも拾っておきたいとか
要するに最低限人に見せられるように整形してからコミットしましょうねということ
対象としては、php-mdやphp-cs-fixerを使ったことのない方だったら
多少ためになるかと思います
Phing
PHPのbuildツールを束ねさせることができる便利なやつ
例えば、下記コマンドを打てばphingが設定ファイル(build.xml)を読み込んで
phpunitやphp-mdなどを実行させることができる。
$ vendor/bin/phing build
実際の実行結果
$ vendor/bin/phing build
Buildfile: /var/www/html/build.xml
プロジェクト名 > hoge:
[...]
プロジェクト名 > phpmd:
[phpmd] Processing files...
[phpmd] Finished processing files
プロジェクト名 > phpunit:
[exec] PHPUnit 4.8.31 by Sebastian Bergmann and contributors.
[exec]
[exec] ....
[exec]
[exec] Time: 205 ms, Memory: 15.00MB
[exec]
[exec] OK (4 tests, 2 assertions)
プロジェクト名 > hoge:
BUILD FINISHED
Total time: 1.0854 second
とこんな感じにコマンド叩けば教えてくれます。
本題
インストール
composer.jsonに下記を追加
phpunitはphpのバージョンに合わせて変えてください
php7系ならば、phpunitのバージョンは5ですかね
今回はphp5.6の前提でいてください
phanを使わないのはphp5.6だからです、、
"require-dev": {
.
.
"phpunit/phpunit": "~4.0",
"phpmd/phpmd" : "*", //コードを静的解析し、命名規則やコードサイズが大きすぎないか等検査するために使用
"phing/phing": "*",
"fabpot/php-cs-fixer": "1.*" //コーディングスタイルを合わせるために使用。psr-2への変換やphpdocを整形できる。設定ファイルは.php_cs
}
$ composer install
補足:シンタックスエラーのチェック
あと、gitでコミット前のステージングファイルにsyntax Errorがないかもついでにチェックしておきたいので
下記のようなスクリプトも用意しました。
#!/usr/bin/env php
<?php
exec('git status -uno --short | grep -E \'^[AUM].*.php$\'| cut -c3-', $changes);
$isError =false;
foreach ($changes as $file) {
$results = [];
exec('php -l '.trim($file), $results);
foreach ($results as $result) {
if (preg_match('/Fatal error/', $result)) {
echo $result . PHP_EOL;
$isError = true;
}
}
}
if (!$isError) {
echo 'Syntax check is OK !!' . PHP_EOL;
}
設定
php-cs-fixer
php5.6 / laravel5.1での設定例
<?php
$finder = Symfony\CS\Finder\DefaultFinder::create()
->exclude('bootstrap/cache')
->exclude('resources/assets')
->exclude('resources/views')
->exclude('resources/lang')
->exclude('storage')
->exclude('vendor')
->exclude('public')
->exclude('node_modules')
->name('*.php')
->in(__DIR__)
->notName('*.blade.php')
->ignoreDotFiles(true);
$fixers = [
'-psr0',
'align_equals', // =の位置を揃える
'align_double_arrow', // => の位置を揃える
'short_array_syntax', // array() → []
'no_empty_phpdoc', // 空のphpdoc禁止.補完ではない
'no_multiline_whitespace_around_double_arrow', // 演算子 => は複数行の空白に囲まれない
'no_multiline_whitespace_before_semicolons', // セミコロンを閉じる前の複数行の空白は禁止
'no_unused_imports', // 未使用のuse文は削除
'ordered_imports', // use文の整列
'single_quote', // 単純な文字列の二重引用符を一重引用符に変換
'standardize_not_equals ', // すべての<>を!=
];
//defaultのコードスタイルは、symfony2
return Symfony\CS\Config\Config::create()
->fixers($fixers)
->finder($finder)
->setUsingCache(true);
phing
build.xmlを追加
<?xml version="1.0" encoding="UTF-8"?>
<project name="プロジェクト名" default="build">
<property name="outputDir" value="./storage/phing/" override="false"/>
<!-- 初期設定 -->
<target name="prepare">
<echo msg="コード静的解析開始...." />
<!--<mkdir dir="./build" />-->
</target>
<!-- コーディングスタイルを合わせる(psr-2など) -->
<target name="php-cs-fixer">
<exec command="vendor/bin/php-cs-fixer fix -v" logoutput="true" />
</target>
<!-- コードの品質を検査 -->
<target name="phpmd">
<exec command="vendor/bin/phpmd ./ text codesize,controversial,design,naming,unusedcode (--exclude 除外したいディレクトリ)" logoutput="true" />
</target>
<!-- コミット予定ファイルからsyntaxError検出 -->
<target name="syntaxCheck">
<exec command="php syntaxCheck" logoutput="true" />
</target>
<!-- ユニットテスト実行 -->
<target name="phpunit">
<exec command="vendor/bin/phpunit" logoutput="true" />
</target>
<target name="build" depends="prepare, php-cs-fixer, phpmd, syntaxCheck, phpunit" /><!-- 実行順序指定 -->
</project>
ディレクトリはこうなります(laravel5.1)
.
├── app
├── artisan
├── bootstrap
├── build.xml //phing 設定
├── composer.json
├── composer.lock
├── config
├── database
├── .env.example
├── .git
├── .gitattributes
├── .gitignore
├── gulpfile.js
├── package.json
├── .php_cs //php-cs-fixer
├── .php_cs.cache //php-cs-fixerのキャッシュ
├── phpspec.yml
├── phpunit.xml
├── public
├── readme.md
├── resources
├── server.php
├── storage
├── syntaxCheck //syntax checkスクリプト
├── tests
└── vendor
実行(laravelプロジェクトで試しに実行)
$ vendor/bin/phing build
Buildfile: /var/www/html/tmp/laravel/build.xml
プロジェクト名 > prepare:
[echo] コード静的解析開始....
プロジェクト名 > php-cs-fixer:
[exec] Loaded config from "/var/www/html/tmp/laravel/.php_cs".
[exec]
[exec] Legend: ?-unknown, I-invalid file syntax, file ignored, .-no changes, F-fixed, E-error
[exec] Fixed all files in 0.261 seconds, 8.750 MB memory used
プロジェクト名 > phpmd:
[exec] /var/www/html/tmp/laravel/app/Exceptions/Handler.php:30 Avoid variables with short names like $e. Configured minimum length is 3.
[exec] /var/www/html/tmp/laravel/app/Exceptions/Handler.php:43 Avoid variables with short names like $e. Configured minimum length is 3.
プロジェクト名 > syntaxCheck:
[exec] Syntax check is OK !!
プロジェクト名 > phpunit:
[exec] PHPUnit 4.8.31 by Sebastian Bergmann and contributors.
[exec]
[exec] E
[exec]
[exec] Time: 1.68 seconds, Memory: 13.50MB
[exec]
[exec] There was 1 error:
[exec]
[exec] 1) ExampleTest::testBasicExample
[exec] RuntimeException: No supported encrypter found. The cipher and / or key length are invalid.
[exec]
[exec] /var/www/html/tmp/laravel/bootstrap/cache/compiled.php:7076
[exec] /var/www/html/tmp/laravel/bootstrap/cache/compiled.php:1289
[exec] /var/www/html/tmp/laravel/bootstrap/cache/compiled.php:1242
[exec] /var/www/html/tmp/laravel/bootstrap/cache/compiled.php:1783
[exec] /var/www/html/tmp/laravel/bootstrap/cache/compiled.php:1334
[exec] /var/www/html/tmp/laravel/bootstrap/cache/compiled.php:1318
[exec] /var/www/html/tmp/laravel/bootstrap/cache/compiled.php:1304
[exec] /var/www/html/tmp/laravel/bootstrap/cache/compiled.php:1242
[exec] /var/www/html/tmp/laravel/bootstrap/cache/compiled.php:1783
[exec] /var/www/html/tmp/laravel/bootstrap/cache/compiled.php:2264
[exec] /var/www/html/tmp/laravel/vendor/laravel/framework/src/Illuminate/Foundation/Testing/CrawlerTrait.php:396
[exec] /var/www/html/tmp/laravel/vendor/laravel/framework/src/Illuminate/Foundation/Testing/InteractsWithPages.php:61
[exec] /var/www/html/tmp/laravel/vendor/laravel/framework/src/Illuminate/Foundation/Testing/InteractsWithPages.php:44
[exec] /var/www/html/tmp/laravel/tests/ExampleTest.php:11
[exec]
[exec] FAILURES!
[exec] Tests: 1, Assertions: 0, Errors: 1.
プロジェクト名 > build:
BUILD FINISHED
Total time: 7.9815 seconds
とまぁ、こんな感じにフィードバックされるようになりました。
まとめ
php-cs-fixerによるコードの修正がかなり助かります。
修正後のファイルを見ると、意識していたけどpsr-2での書き方できてなかったりと気づきがありました。
phpdocも統一されたフォーマットで書き換えてくれるのでとてもありがたいです。
CircleCIやジェンキンスまでいくとハードル高いかもしれませんがこんな感じで
手軽にコードチェックでも整った開発がしていけそうですね。
今年最後の投稿になりそうです、読んでいただきありがとうございます。
良いお年を。。
下記参考にしました、ありがとうございます。
http://qiita.com/nyanchu/items/d881c34c3112a2ffcdf6
追記
php-cs-fixerは、--dry-runとすることでファイル変換はせずに警告表示だけにすることもできます