Laravelにphpcs(PHP_CodeSniffer)を導入する

2024/02/03に公開

みなさん静的解析で "ラク" してますか?

PHPにもいくつか静的解析ツールがあります。どんなものがあるのかは以下のような記事を見てみてください。
PHPerのための「静的解析」を語り合う【PHP TechCafe イベントレポート】

他のツールは特に使っていないので比較はできませんが、とりあえず以下の理由でPHP_CodeSniffer導入してみました。

  1. composer でシュッと入れられそう
  2. phpcs.xml で設定をチャチャっと書けそう

導入手順

導入の仕方は自由ですがcomposer経由での導入の仕方を参考までに載せておきます。
詳細はPHP_CodeSnifferの公式ドキュメントをご覧ください。

PHP_CodeSnifferの導入

ご自身のLaravelプロジェクトで以下を実行してください。

$ composer require --dev squizlabs/php_codesniffer

VariableAnalysis と Slevomat Coding Standard の導入

PHP_CodeSniffer だけでは痒いところに手が届かなかったので追加でこちらのcomposerも導入しました。

$ composer require slevomat/coding-standard --dev
$ composer require sirbrillig/phpcs-variable-analysis- -dev 

phpcs.xml の設定

現時点での我々が使っている phpcs.xml を載せておきます。
phpcsの個別の設定の詳細に関してはPHP_CodeSnifferのルールまとめをご参照ください。

<?xml version="1.0"?>
<ruleset name="PSR12/Laravel">
    <description>PSR12 compliant rules and settings for Laravel</description>

    <arg name="extensions" value="php" />

    <!-- コーディング規約指定 -->
    <rule ref="PSR12">
      <!--<exclude name="Generic.Files.LineLength"/>-->
    </rule>
    <arg name="colors" />
    <arg value="ps" />

    <!-- 除外ディレクトリ設定 -->
    <exclude-pattern>/bootstrap/</exclude-pattern>
    <exclude-pattern>/node_modules/</exclude-pattern>
    <exclude-pattern>/public/</exclude-pattern>
    <exclude-pattern>/resources/</exclude-pattern>
    <exclude-pattern>/storage/</exclude-pattern>
    <exclude-pattern>/vendor/</exclude-pattern>
    <exclude-pattern>/server.php</exclude-pattern>
    <exclude-pattern>/app/Console/Kernel.php</exclude-pattern>
    <exclude-pattern>/tests/CreatesApplication.php</exclude-pattern>

    <rule ref="Generic.Files.LineLength">
        <properties>
            <property name="lineLimit" value="140"/>
            <property name="absoluteLineLimit" value="160"/>
        </properties>
    </rule>

    <rule ref="PSR1.Methods.CamelCapsMethodName.NotCamelCaps">
        <exclude-pattern>*/tests/*</exclude-pattern>
    </rule>

    <rule ref="PSR1.Classes.ClassDeclaration.MissingNamespace">
        <exclude-pattern>./database/migrations/*</exclude-pattern>
    </rule>

    <rule ref="Generic.PHP.Syntax" />
    <rule ref="Generic.Arrays.DisallowLongArraySyntax" />
    <rule ref="Generic.CodeAnalysis.UnconditionalIfStatement" />
    <rule ref="Generic.CodeAnalysis.UselessOverridingMethod" />
    <rule ref="Generic.ControlStructures.DisallowYodaConditions" />
    <rule ref="Generic.Formatting.SpaceAfterCast" />
    <rule ref="Generic.PHP.DeprecatedFunctions" />
    <rule ref="Generic.PHP.ForbiddenFunctions" />
    <rule ref="Generic.VersionControl.GitMergeConflict" />
    <rule ref="Generic.WhiteSpace.ArbitraryParenthesesSpacing" />
    <rule ref="Generic.WhiteSpace.LanguageConstructSpacing" />
    <rule ref="Generic.WhiteSpace.SpreadOperatorSpacingAfter" />
    <rule ref="Squiz.WhiteSpace.FunctionSpacing">
        <properties>
            <property name="spacing" value="1" />
            <property name="spacingBeforeFirst" value="0" />
            <property name="spacingAfterLast" value="0" />
        </properties>
    </rule>
    <rule ref="Squiz.WhiteSpace.SemicolonSpacing" />

    <!-- coding-standard https://github.com/slevomat/coding-standard -->
    <rule ref="SlevomatCodingStandard.PHP.UselessParentheses" />
    <rule ref="SlevomatCodingStandard.PHP.UselessSemicolon" />
    <rule ref="SlevomatCodingStandard.Namespaces.UnusedUses" />
    <rule ref="SlevomatCodingStandard.Whitespaces.DuplicateSpaces">
        <properties>
            <property name="ignoreSpacesBeforeAssignment" value="true"/>
            <property name="ignoreSpacesInParameters" value="true"/>
            <property name="ignoreSpacesInAnnotation" value="true"/>
            <property name="ignoreSpacesInComment" value="true"/>
        </properties>
    </rule>
    <rule ref="SlevomatCodingStandard.Arrays.SingleLineArrayWhitespace" />

    <!-- phpcs-variable-analysis https://github.com/sirbrillig/phpcs-variable-analysis -->
    <rule ref="VariableAnalysis">
        <properties>
            <property name="ignoreUnusedRegexp" value="/^_/"/>
            <property name="allowUnusedParametersBeforeUsed" value="false"/>
        </properties>
    </rule>
</ruleset>

これを設定しておくと主に以下のようなものを検知してくれます。

  • syntaxエラー
  • 変数名がスネークケースか
  • 関数名がキャメルケースか
  • 使われていない変数
  • 不自然な空白

などなどを調べてくれるので非常に助かります。
それ以外のものに関してはパラメータを調べつつ

PHP_CodeSnifferの実行

composer.json に以下を追加しましょう。

"scripts": {
    "phpcs": [
      "./vendor/bin/phpcs --standard=phpcs.xml"
    ]
}

以下を実行すると静的解析が走るはずです。

$ composer phpcs .

私の場合はテキストエディタにvimを使っているのでALEでファイル保存時に自動的に静的解析が走るようにしています。VSCodeとかでもおそらくあると思うので調べてみてください。

CIツールを入れているのであればPRに変更があった時に実行するように設定してみてください。
我々は GitHub Actions を入れているのでそちらで実行されるようにしています。

余談

ちなみにphpcsとは関係ないですが、英単語の誤字脱字のチェックに以下も導入しています。

まだまだ試行錯誤しながら設定中なので、こう言う設定も入れると便利だよーとか何かあれば教えて欲しいです!!

Discussion