私の vim 環境では ALE (Asynchronous Lint Engine) で非同期構文チェックをしている.
デフォルトだと全ての lint tools が走るので, 特定のツールだけ走るように設定する.
今回は phpmd, phpcs について.
概要は次の通り.
動作環境
- macOS Mojave 10.14.x
- vim 8.1
今回やりたいこと
コードを書く時に構文解析をしたい.
php に関しては phpcs, phpmd を利用して規約チェックもしたい.
多くの場合, この辺のルールはプロジェクト毎に異なるので local に落としてきたプロジェクトディレクトリに設定する.
phpcs, phpmd どちらもカスタマイズして使う予定.
inst. 方法というよりもカスタマイズ方法に注力してまとめてゆく.
前提条件
- composer inst. 済
- PATH も通しておくこと
- 躓いたら公式サイトやヘルプを眺める
事前に ale のヘルプを読めるようにしておくといいかも.
Generating Vim help files
You can add the following line to your vimrc files to generate documentation tags automatically, if you don’t have something similar already, so you can use the
:help
command to consult ALE’s online documentation:” Put these lines at the very end of your vimrc file.
” Load all plugins now.
” Plugins need to be added to runtimepath before helptags can be generated.
packloadall
” Load all of the helptags now, after plugins have been loaded.
” All messages and errors will be ignored.
silent! helptags ALL
phpmd, phpcs の簡単な説明
phpmd, phpcs ができることをざっとまとめる.
phpmd
- 公式サイト
できることは次の通り.
What PHPMD does is: It takes a given PHP source code base and look for several potential problems within that source. These problems can be things like:
- Possible bugs
- Suboptimal code
- Overcomplicated expressions
- Unused parameters, methods, properties
未使用変数, 長過ぎるプロパティ名等をチェックしてくれる.
phpcs
できることは次の通り.
PHP_CodeSniffer is a set of two PHP scripts; the main
phpcs
script that tokenizes PHP, JavaScript and CSS files to detect violations of a defined coding standard,
and a secondphpcbf
script to automatically correct coding standard violations.
PHP_CodeSniffer is an essential development tool that ensures your code remains clean and consistent.
コーディング規約違反を静的に検出してくれる.
phpmd カスタマイズ
install
公式サイトに従って inst.
global inst. したいなら次のコマンドでもいいかも.
$ composer global require phpmd/phpmd
カスタマイズ
必要なルールだけチェックしてほしいのでカスタマイズする.
公式サイトにカスタマイズ方針も書かれている.
default のルールセット置き場はここ↓
vendor/phpmd/phpmd/src/main/resources/rulesets/
置いてある xml は次の通り.
- cleancode.xml
- codesize.xml
- controversial.xml
- design.xml
- naming.xml
- unusedcode.xml
各ファイルについての説明はここに書いてある↓
- Clean Code Rules
- The Clean Code ruleset contains rules that enforce a clean code base. This includes rules from SOLID and object calisthenics.
- Code Size Rules
- The Code Size Ruleset contains a collection of rules that find code size related problems.
- Controversial Rules
- This ruleset contains a collection of controversial rules.
- Design Rules
- The Design Ruleset contains a collection of rules that find software design related problems.
- Naming Rules
- The Naming Ruleset contains a collection of rules about names – too long, too short, and so forth.
- Unused Code Rules
- The Unused Code Ruleset contains a collection of rules that find unused code.
引用: Current Rulesets
ひとまず .vimrc に phpmd 実行パスを指定する.
実行パスは $ which phpmd
で調査可能.
このあたりの情報は :h ale-php-phpmd
で入手可能.
let g:ale_php_phpmd_executable = 'ここに $ which phpmd で得られる path を入力'
この時点で php ファイルを編集するとたとえば次のような warning が得られる.
Avoid using static access to class ‘\Illuminate\Support\Facades\Config’ in method ‘get’.
↑これは cleancode.xml の条件に引っかかって出力されたメッセージ.
特定の .xml だけを有効/無効にすることも可能.
たとえば controversial.xml
のみ無効にするとこうなる↓
let g:ale_php_phpmd_ruleset = 'cleancode,codesize,design,naming'
各 rule sets 内で特定の rule を除外する手段は次のいずれか.
- 直接 xml を編集
- おれおれ xml を作成し, 既存 xml を呼び出し, さらに特定 rule を除外
今回は後者で対応する.
たとえば先程の static method に対する warning を除外するには <exclude name="StaticAccess" />
を利用すればいい.
試しに myphpmd.xml
という新規ファイルを作成してみる.
<?xml version="1.0"?>
<ruleset
name="My PHPMD rule set"
xmlns="http://pmd.sf.net/ruleset/1.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://pmd.sf.net/ruleset/1.0.0 http://pmd.sf.net/ruleset_xml_schema.xsd"
xsi:noNamespaceSchemaLocation="http://pmd.sf.net/ruleset_xml_schema.xsd">
<description>
My PHPMD rule set
</description>
<!-- import rulesets -->
<rule ref="rulesets/unusedcode.xml" />
<rule ref="rulesets/cleancode.xml">
<exclude name="StaticAccess" />
</rule>
<rule ref="rulesets/codesize.xml" />
<rule ref="rulesets/design.xml" />
<rule ref="rulesets/naming.xml" />
</ruleset>
もしこの ruleset を利用する場合は, 先程の phpmd ruleset 指定を変更する必要がある.
let g:ale_php_phpmd_ruleset = 'myphpmd'
こんな具合に不要な warning を除外していけば使いやくすくなるはず.
phpcs カスタマイズ
次は phpcs を ale 使う方法について.
install
composer で global に inst.
$ composer global require "squizlabs/php_codesniffer=*"
バージョンはプロジェクトに合わせて設定すること.
composer で必要な PATH は通しておくこと.
カスタマイズ
チェックする rule のカスタマイズについては PHP_CodeSniffer の wiki を参考にする.
各規約は次の場所に格納されている.
- vendor/squizlabs/php_codesniffer/src/Standards/
規約は次のコマンドでも確認可能.
$ phpcs -i
デフォルトだと PEAR が standard として設定されているっぽい.
.vimrc で PSR-2 を指定.
let g:ale_php_phpcs_standard = 'PSR2'
これで PSR2 に従った warning や error が出力される.
phpmd 同様, 一度全ての rule を適用して不要なものを外してゆくと効率がいいかも.
個人的には PEAR, PSR2 の standard から不要な warning, error を外してゆくのがいいと思っている.
やってみる.
まず MyPSR2
というディレクトリを作成.
# ディレクトリごとコピー
$ cp -r PSR2 MyPSR2
# standards 確認
$ phpcs -i
The installed coding standards are PEAR, Zend, PSR2, MySource, Squiz, PSR1, MyPSR2 and PSR12
# MyPSR2 内にあるディレクトリの中身は不要なので空にする
$ rm -rf Docs/* Sniffs/* Tests/*
# ディレクトリ構成確認
$ ls -lah
total 24
drwxr-xr-x 6 kengo staff 192B 2 2 20:04 .
drwxr-xr-x 11 kengo staff 352B 2 2 20:04 ..
drwxr-xr-x 2 kengo staff 64B 2 2 20:10 Docs
drwxr-xr-x 2 kengo staff 64B 2 2 20:10 Sniffs
drwxr-xr-x 2 kengo staff 64B 2 2 20:10 Tests
-rw-r--r-- 1 kengo staff 10K 2 2 20:04 ruleset.xml
次に ruleset.xml を編集してゆく.
ゴールは PEAR, PSR2 のいいとこ取りだが, 一先ず PSR2 のみ include しておく.
後々除外する warning 等が出てくるだろうから次のような構成にした.
<?xml version="1.0"?>
<ruleset xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" name="MyPSR2" xsi:noNamespaceSchemaLocation="../../../phpcs.xsd">
<description>MyPSR-2 coding standard</description>
<!-- Include the whole PSR-2 standard -->
<rule ref="PSR2">
</rule>
</ruleset>
ここまでできたら .vimrc で MyPSR2
を指定する.
let g:ale_php_phpcs_standard = 'MyPSR2'
phpcbf もこれまで同様に設定しておくと大量に warnings が出たときに修正が楽になる.
:ALEFix
コマンドはここで力を発揮する.
ただし, この自動変換はプロジェクトに依存するところが大きいので取扱い注意.
今回の作業で追記した .vimrc
少し無関係の箇所もあるけど, 一旦 .vimrc の変更点もまとめる.
"" set linters
let g:ale_linters = {
\ 'php': ['phpcs', 'phpmd', 'php -l'],
\ 'python': ['pylint']
\}
"" phpmd
let g:ale_php_phpmd_executable = '/path/to/phpmd'
let g:ale_php_phpmd_ruleset = 'myphpmd'
""" keymaps
""" jump to next/previous warning
nmap <silent> <C-k> <Plug>(ale_previous_wrap)
nmap <silent> <C-j> <Plug>(ale_next_wrap)
"" phpcs
let g:ale_php_phpcs_executable = '/path/to/phpcs'
let g:ale_php_phpcs_standard = 'MyPSR2'
"" phpcbf
let g:ale_php_phpcbf_executable = '/path/to/phpcbf'
let g:ale_php_phpcbf_standard = 'PSR2'
"" fixer
let g:ale_fixers = {
\ 'php': ['phpcbf']
\}
まとめ
基本的には公式サイトに全部手順が書いてあるけど, 実際手を動かしてみないと分からないことが多い.
たとえば次のようなもの.
- プロジェクト毎に作成した オレオレphpmd.xml 管理方法
vendor/
配下の特定 dir. を git 管理したり ?
- ale による静的解析やコード整形の実行タイミング
このあたりは実際に運用しながらカスタマイズしてゆけばいいかな.
今回は以上.