PHP_CodeSnifferの導入

[グレンジ Advent Calendar 2017](https://qiita.com/advent-calendar/2017/grenge) 5日目の記事を担当の jinjin1 です。
グレンジでサーバサイドエンジニアをしています。

今回は、[PHP_CodeSniffer](https://github.com/squizlabs/PHP_CodeSniffer)の導入で設定した内容についてです。

## インストール

composerでインストールしました。

```composer.json
	"require-dev" : {
		"squizlabs/php_codesniffer" : "2.*"
	}
```

## 設定

ディレクトリ構成は以下のような形にしました。

```
├── app (対象となるソースコード)
├── rules
│   ├── php_codesniffer.xml (実行する対象や除外を定義)
│   └── php_codesniffer
│       └── standards
│           └── Custom
│               └── ruleset.xml (独自のカスタムコード規約)
└── vendor
```

「Custom」というrulesetを作成し、独自の定義を記述しています。
「PSR2」をベースに、元々あったコードフォーマットに合わせ除外や追加をしています。

```rules/php_codesniffer/standards/Custom/ruleset.xml
<?xml version="1.0"?>
<ruleset name="Custom">

    <description>A custom coding standard.</description>

    <rule ref="PSR2">

        <!-- 名前空間のチェックなし -->
        <exclude name="PSR1.Classes.ClassDeclaration"/>

        <!-- １行あたりの文字数チェックなし -->
        <exclude name="Generic.Files.LineLength"/>

        <!-- クラスの開き括弧を次の行に記述しない -->
        <exclude name="PSR2.Classes.ClassDeclaration"/>

        <!-- メソッドの開き括弧を次の行に記述しない -->
        <exclude name="Squiz.Functions.MultiLineFunctionDeclaration"/>

        <!-- elseifのチェックなし -->
        <exclude name="PSR2.ControlStructures.ElseIfDeclaration"/>

    </rule>

    <!-- elseif でなく else if を使用する -->
    <rule ref="Squiz.ControlStructures.ElseIfDeclaration"/>

    <!-- 二項演算子の前後にスペース -->
    <rule ref="Squiz.WhiteSpace.OperatorSpacing" />

    <!-- セミコロンの前にスペースを入れない -->
    <rule ref="Squiz.WhiteSpace.SemicolonSpacing.Incorrect"/>

    <!-- ファンクションの開始ブレス直後に空行を入れない -->
    <rule ref="Squiz.WhiteSpace.FunctionOpeningBraceSpace.SpacingAfter"/>

    <!-- array()禁止 []を使うこと -->
    <rule ref="Generic.Arrays.DisallowLongArraySyntax.Found"/>

    <!-- キャスト演算子と変数の間にスペースがあってはならない -->
    <rule ref="Generic.Formatting.NoSpaceAfterCast.SpaceFound"/>

    <!-- 配列の最終行にカンマが必要 -->
    <rule ref="Squiz.Arrays.ArrayDeclaration.NoCommaAfterLast">
        <exclude name="Squiz.Arrays.ArrayDeclaration.CloseBraceNotAligned"/>
        <exclude name="Squiz.Arrays.ArrayDeclaration.KeyNotAligned"/>
        <exclude name="Squiz.Arrays.ArrayDeclaration.MultiLineNotAllowed"/>
        <exclude name="Squiz.Arrays.ArrayDeclaration.NoSpaceAfterComma"/>
        <exclude name="Squiz.Arrays.ArrayDeclaration.SingleLineNotAllowed"/>
        <exclude name="Squiz.Arrays.ArrayDeclaration.ValueNoNewline"/>
        <exclude name="Squiz.Arrays.ArrayDeclaration.ValueNotAligned"/>
    </rule>

    <!-- 空配列はスペース空けない -->
    <rule ref="Squiz.Arrays.ArrayDeclaration.SpaceInEmptyArray"/>

    <!-- 行末に不要なスペースを入れない -->
    <rule ref="Squiz.WhiteSpace.SuperfluousWhitespace">
        <properties>
            <property name="ignoreBlankLines" value="false"/>
        </properties>
    </rule>

    <!-- 言語の制御構造の後ろにスペース -->
    <rule ref="Squiz.WhiteSpace.LanguageConstructSpacing.Incorrect"/>

    <!-- ファンクションの前後は改行をいれる -->
    <rule ref="Squiz.WhiteSpace.FunctionSpacing" >
        <properties>
            <property name="spacing" value="1" />
        </properties>
    </rule>

    <!-- 必要のないまたは到達できないreturn -->
    <rule ref="Squiz.PHP.NonExecutableCode.ReturnNotRequired"/>

    <!-- ダブルコーテーション使わない -->
    <rule ref="Squiz.Strings.DoubleQuoteUsage.NotRequired">
        <exclude name="Squiz.Strings.DoubleQuoteUsage.ContainsVar"/>
    </rule>

</ruleset>
```

実行時に指定する定義ファイルには、対象ディレクトリや除外するファイル、対象ごとの除外ルールを記述しています。

```rules/php_codesniffer.xml
<?xml version="1.0"?>
<ruleset name="Custom">

    <description>A custom coding standard.</description>

    <file>app</file>
    <file>tests</file>

    <exclude-pattern>app/cli.php</exclude-pattern>
    <exclude-pattern>app/cache</exclude-pattern>

    <arg name="colors"/>
    <arg value="sp"/>

    <rule ref="./php_codesniffer/standards/Custom"/>

    <rule ref="PSR1.Methods.CamelCapsMethodName">

        <!-- テストは除外 -->
        <exclude-pattern>tests</exclude-pattern>

    </rule>

    <rule ref="Squiz.WhiteSpace.OperatorSpacing">

        <!-- 設定ファイルは除外 -->
        <exclude-pattern>config.php</exclude-pattern>

    </rule>

    <rule ref="Squiz.WhiteSpace.LanguageConstructSpacing.Incorrect">

        <!-- 設定ファイルは除外 -->
        <exclude-pattern>app/config/</exclude-pattern>

    </rule>

</ruleset>
```

## 実行

rules/php_codesniffer.xml を指定して実行します。

```
./vendor/bin/phpcs --standard=rules/php_codesniffer.xml
```