PHP_CodeSniffer

コード品質リンターPHPDevOps静的解析PSRコーディング規約

DevOpsツール

PHP_CodeSniffer

概要

PHP_CodeSnifferは、PHPファイルをトークン化し、定義されたコーディング規約の違反を検出するPHP専用の静的コード解析ツールです。PSR-12などの標準規約に準拠したコード品質チェックを実現し、phpcsによる違反検出とphpcbfによる自動修正の2つのツールで構成。PHP、JavaScript、CSSファイルに対応し、GitHub Artifact Attestationsによる署名検証機能も追加。2025年版では新しいPHPCSStandards組織による開発継続とセキュリティ強化により、PHP開発における標準的なコード品質管理ツールとして進化しています。

詳細

PHP_CodeSniffer(ピーエイチピーコードスニファー、PHPCS)は、元々Squiz Labs社によって開発されたPHP用静的コード解析ツールですが、2025年現在はPHPCSStandards組織によってメンテナンスが継続されています。PHP開発において、PSR-12等のコーディング規約準拠を強制し、コード品質の一貫性を保つ業界標準ツールです。

主要な特徴

  • 包括的なコード解析: PHP、JavaScript、CSSファイルのトークン化と解析
  • PSR標準完全対応: PSR-1、PSR-2、PSR-12等のPHP標準規約準拠
  • 二重ツール構成: phpcs(検出)とphpcbf(自動修正)の組み合わせ
  • カスタム規約対応: 独自コーディング規約の定義と適用機能
  • セキュリティ強化: PHAR署名とGitHub Artifact Attestations検証
  • IDE統合: PhpStorm、VS Code等の主要エディター対応
  • CI/CD統合: Jenkins、GitHub Actions等での自動品質チェック
  • 柔軟な設定: phpcs.xml設定ファイルによる詳細カスタマイズ
  • レポート機能: XML、JSON、HTML等の多様な出力形式

2025年版の新機能

  • 新組織運営: PHPCSStandards組織による積極的メンテナンス
  • 署名検証: GitHub Artifact AttestationsによるPHAR検証機能
  • クロスバージョン互換性: PHP Compatibility Coding Standardの統合
  • 強化されたレポート: CI/CDパイプライン最適化のXMLサマリーレポート

メリット・デメリット

メリット

  • PHP開発での業界標準コーディング規約の自動強制
  • PSR-12準拠によるモダンPHPコードの品質保証
  • phpcbf自動修正機能による手動修正作業の大幅削減
  • 多様なコーディング規約への対応による柔軟性
  • IDE統合によるリアルタイムコード品質フィードバック
  • CI/CD統合による自動化された品質ゲート実現
  • カスタム規約定義による企業・プロジェクト固有要件対応
  • 豊富なレポート形式による品質状況の可視化
  • セキュリティ強化による信頼性の高いツール配布
  • PHP、JavaScript、CSS対応による統一的品質管理

デメリット

  • 大規模レガシーコードベースでの大量警告による導入負荷
  • 過度な規約強制による開発速度低下のリスク
  • カスタム規約作成の複雑さと学習コスト
  • 実行時間の長さ(特に大規模プロジェクト)
  • 元リポジトリ廃止による混乱と移行作業
  • PHP専用のため多言語プロジェクトでの統一ツール使用制限
  • 一部自動修正の不完全性(手動確認が必要)
  • チーム内でのコーディング規約合意形成の必要性
  • 設定ファイルの複雑化によるメンテナンス負荷
  • 古いバージョンのPHPサポート制限

参考ページ

書き方の例

インストールと基本セットアップ

Composer経由でのインストール

# プロジェクトローカルインストール(推奨)
composer require --dev squizlabs/php_codesniffer

# グローバルインストール
composer global require squizlabs/php_codesniffer

# 特定バージョン指定
composer require --dev "squizlabs/php_codesniffer:^3.10"

# インストール確認
./vendor/bin/phpcs --version
./vendor/bin/phpcbf --version

# グローバルインストール確認
phpcs --version
phpcbf --version

PHAR経由でのインストール

# PHARファイルダウンロード
curl -OL https://phars.phpcodesniffer.com/phpcs.phar
curl -OL https://phars.phpcodesniffer.com/phpcbf.phar

# 実行権限付与
chmod +x phpcs.phar phpcbf.phar

# システムPATHに配置
sudo mv phpcs.phar /usr/local/bin/phpcs
sudo mv phpcbf.phar /usr/local/bin/phpcbf

# GitHub Artifact Attestations検証(2025年新機能)
gh attestation verify phpcs.phar --owner PHPCSStandards

# 署名検証
gpg --verify phpcs.phar.asc phpcs.phar

基本的な実行方法

# 基本実行
./vendor/bin/phpcs src/

# 特定ファイルのチェック
./vendor/bin/phpcs src/User.php

# PSR-12標準でのチェック
./vendor/bin/phpcs --standard=PSR12 src/

# 複数標準の組み合わせ
./vendor/bin/phpcs --standard=PSR12,Generic.Files.LineLength src/

# 詳細出力
./vendor/bin/phpcs -v src/

# プログレス表示
./vendor/bin/phpcs -p src/

# 色付き出力
./vendor/bin/phpcs --colors src/

# 特定拡張子のみ
./vendor/bin/phpcs --extensions=php,js src/

# 除外パターン指定
./vendor/bin/phpcs --ignore=*/tests/*,*/vendor/* src/

# レポート形式指定
./vendor/bin/phpcs --report=summary src/
./vendor/bin/phpcs --report=xml src/
./vendor/bin/phpcs --report=json src/

自動修正(phpcbf)

# 基本自動修正
./vendor/bin/phpcbf src/

# 特定標準で修正
./vendor/bin/phpcbf --standard=PSR12 src/

# ドライラン(変更内容確認)
./vendor/bin/phpcbf --dry-run src/

# 詳細出力付き修正
./vendor/bin/phpcbf -v src/

# 特定ファイルのみ修正
./vendor/bin/phpcbf src/Models/User.php

# バックアップ作成付き修正
./vendor/bin/phpcbf --suffix=.bak src/

設定ファイル(phpcs.xml)

<?xml version="1.0"?>
<ruleset name="Custom PHP Standards">
    <description>プロジェクト用PHP コーディング規約</description>

    <!-- 対象ファイル -->
    <file>src</file>
    <file>tests</file>

    <!-- 除外パターン -->
    <exclude-pattern>*/vendor/*</exclude-pattern>
    <exclude-pattern>*/node_modules/*</exclude-pattern>
    <exclude-pattern>*.min.js</exclude-pattern>
    <exclude-pattern>*/migrations/*</exclude-pattern>

    <!-- PSR-12 基本規約 -->
    <rule ref="PSR12">
        <!-- 特定ルールの除外 -->
        <exclude name="PSR12.Files.FileHeader.SpacingAfterBlock"/>
    </rule>

    <!-- 追加規約 -->
    <rule ref="Generic.Files.LineLength">
        <properties>
            <property name="lineLimit" value="120"/>
            <property name="absoluteLineLimit" value="150"/>
        </properties>
    </rule>

    <rule ref="Generic.Metrics.CyclomaticComplexity">
        <properties>
            <property name="complexity" value="10"/>
            <property name="absoluteComplexity" value="15"/>
        </properties>
    </rule>

    <rule ref="Generic.Metrics.NestingLevel">
        <properties>
            <property name="nestingLevel" value="5"/>
            <property name="absoluteNestingLevel" value="8"/>
        </properties>
    </rule>

    <!-- カスタムルール -->
    <rule ref="Squiz.PHP.ForbiddenFunctions">
        <properties>
            <property name="forbiddenFunctions" type="array">
                <element key="eval" value="null"/>
                <element key="exec" value="null"/>
                <element key="shell_exec" value="null"/>
                <element key="var_dump" value="null"/>
                <element key="print_r" value="null"/>
            </property>
        </properties>
    </rule>

    <!-- 設定オプション -->
    <arg name="colors"/>
    <arg name="parallel" value="8"/>
    <arg value="p"/>

    <!-- PHP バージョン設定 -->
    <config name="php_version" value="80100"/>
</ruleset>

Laravel プロジェクト用設定

<?xml version="1.0"?>
<ruleset name="Laravel Project Standards">
    <description>Laravel プロジェクト用コーディング規約</description>

    <!-- Laravel ディレクトリ構造 -->
    <file>app</file>
    <file>config</file>
    <file>database</file>
    <file>routes</file>
    <file>tests</file>

    <!-- Laravel 除外パターン -->
    <exclude-pattern>*/vendor/*</exclude-pattern>
    <exclude-pattern>*/storage/*</exclude-pattern>
    <exclude-pattern>*/bootstrap/cache/*</exclude-pattern>
    <exclude-pattern>*/node_modules/*</exclude-pattern>
    <exclude-pattern>*/public/hot</exclude-pattern>
    <exclude-pattern>*/public/storage</exclude-pattern>
    <exclude-pattern>*/.phpstorm.meta.php</exclude-pattern>
    <exclude-pattern>*/_ide_helper.php</exclude-pattern>

    <!-- PSR-12 + Laravel 固有調整 -->
    <rule ref="PSR12"/>

    <!-- Laravel Eloquent モデル用調整 -->
    <rule ref="PSR1.Classes.ClassDeclaration.MissingNamespace">
        <exclude-pattern>*/database/migrations/*</exclude-pattern>
        <exclude-pattern>*/database/seeders/*</exclude-pattern>
    </rule>

    <!-- Blade テンプレート用設定 -->
    <rule ref="Generic.Files.LineLength">
        <exclude-pattern>*.blade.php</exclude-pattern>
    </rule>

    <!-- Laravel Configuration -->
    <rule ref="Generic.Arrays.DisallowLongArraySyntax"/>
    <rule ref="Generic.PHP.ForbiddenFunctions">
        <properties>
            <property name="forbiddenFunctions" type="array">
                <element key="dd" value="null"/>
                <element key="dump" value="null"/>
                <element key="var_dump" value="null"/>
            </property>
        </properties>
        <exclude-pattern>*/tests/*</exclude-pattern>
    </rule>
</ruleset>

CI/CD統合例

GitHub Actions

# .github/workflows/phpcs.yml
name: PHP CodeSniffer

on:
  push:
    branches: [ main, develop ]
  pull_request:
    branches: [ main ]

jobs:
  phpcs:
    runs-on: ubuntu-latest
    
    steps:
    - name: Checkout code
      uses: actions/checkout@v4
    
    - name: Setup PHP
      uses: shivammathur/setup-php@v2
      with:
        php-version: '8.2'
        tools: composer
        coverage: none
    
    - name: Cache Composer dependencies
      uses: actions/cache@v4
      with:
        path: vendor
        key: ${{ runner.os }}-composer-${{ hashFiles('**/composer.lock') }}
        restore-keys: ${{ runner.os }}-composer-
    
    - name: Install dependencies
      run: composer install --prefer-dist --no-progress --no-suggest
    
    - name: Run PHP CodeSniffer
      run: ./vendor/bin/phpcs --standard=PSR12 --report=github src/
    
    - name: Auto-fix with PHP CBF (if push to main)
      if: github.ref == 'refs/heads/main' && github.event_name == 'push'
      run: |
        ./vendor/bin/phpcbf --standard=PSR12 src/
        if [ -n "$(git status --porcelain)" ]; then
          git config --local user.email "[email protected]"
          git config --local user.name "GitHub Action"
          git add -A
          git commit -m "Auto-fix PHP CodeSniffer violations" -a
          git push
        fi

GitLab CI/CD

# .gitlab-ci.yml
variables:
  COMPOSER_CACHE_DIR: ".composer-cache"

cache:
  key: composer-cache
  paths:
    - .composer-cache/

stages:
  - quality

phpcs:
  stage: quality
  image: php:8.2-alpine
  before_script:
    - apk add --no-cache git
    - curl -sS https://getcomposer.org/installer | php
    - php composer.phar install --prefer-dist --no-progress --no-suggest
  script:
    - ./vendor/bin/phpcs --standard=PSR12 --report=gitlab src/
    - ./vendor/bin/phpcs --standard=PSR12 --report=xml --report-file=phpcs-report.xml src/
  artifacts:
    reports:
      codequality: phpcs-report.xml
    paths:
      - phpcs-report.xml
    expire_in: 1 week
  only:
    - main
    - develop
    - merge_requests

IDE統合設定

PhpStorm設定

# PhpStorm設定手順
# File → Settings → PHP → Quality Tools → PHP_CodeSniffer

# Configuration path:
# ローカル: ./vendor/bin/phpcs
# グローバル: /usr/local/bin/phpcs

# Coding standard: PSR12
# または custom: ./phpcs.xml

# 自動実行設定
# File → Settings → Editor → Inspections → PHP → Quality tools
# PHP_CodeSniffer validation をチェック

# External Tools設定
# File → Settings → Tools → External Tools → Add
Name: PHP_CodeSniffer
Description: PHP Code quality checker
Program: $ProjectFileDir$/vendor/bin/phpcs
Arguments: --standard=PSR12 $FilePath$
Working Directory: $ProjectFileDir$

Name: PHP_CBF
Description: PHP Code auto-fixer
Program: $ProjectFileDir$/vendor/bin/phpcbf
Arguments: --standard=PSR12 $FilePath$
Working Directory: $ProjectFileDir$

VS Code設定

// .vscode/settings.json
{
  "php.validate.executablePath": "/usr/bin/php",
  "phpcs.enable": true,
  "phpcs.executablePath": "./vendor/bin/phpcs",
  "phpcs.standard": "PSR12",
  "phpcbf.enable": true,
  "phpcbf.executablePath": "./vendor/bin/phpcbf",
  "phpcbf.standard": "PSR12",
  "phpcbf.onsave": true,
  "[php]": {
    "editor.defaultFormatter": "bmewburn.vscode-intelephense-client",
    "editor.formatOnSave": true,
    "editor.rulers": [120]
  },
  "files.associations": {
    "*.php": "php"
  }
}

// tasks.json for VS Code tasks
{
  "version": "2.0.0",
  "tasks": [
    {
      "label": "PHP CodeSniffer",
      "type": "shell",
      "command": "./vendor/bin/phpcs",
      "args": ["--standard=PSR12", "src/"],
      "group": "build",
      "presentation": {
        "echo": true,
        "reveal": "always",
        "focus": false,
        "panel": "shared"
      }
    },
    {
      "label": "PHP CBF Auto-fix",
      "type": "shell",
      "command": "./vendor/bin/phpcbf",
      "args": ["--standard=PSR12", "src/"],
      "group": "build"
    }
  ]
}

カスタムスニフ(独自ルール)作成

<?php
// CustomSniffs/Sniffs/Functions/ForbiddenFunctionsSniff.php

namespace CustomSniffs\Sniffs\Functions;

use PHP_CodeSniffer\Sniffs\Sniff;
use PHP_CodeSniffer\Files\File;

class ForbiddenFunctionsSniff implements Sniff
{
    /**
     * 禁止関数一覧
     */
    public $forbiddenFunctions = [
        'eval',
        'exec',
        'shell_exec',
        'system',
        'passthru',
        'var_dump',
        'print_r',
        'debug_print_backtrace',
    ];

    /**
     * 監視するトークン
     */
    public function register()
    {
        return [T_STRING];
    }

    /**
     * トークン処理
     */
    public function process(File $phpcsFile, $stackPtr)
    {
        $tokens = $phpcsFile->getTokens();
        $functionName = $tokens[$stackPtr]['content'];

        if (!in_array($functionName, $this->forbiddenFunctions)) {
            return;
        }

        // 関数呼び出しかチェック
        $nextToken = $phpcsFile->findNext(T_WHITESPACE, ($stackPtr + 1), null, true);
        if ($tokens[$nextToken]['code'] !== T_OPEN_PARENTHESIS) {
            return;
        }

        $error = 'Forbidden function "%s" found. Use alternative approach.';
        $data = [$functionName];
        $phpcsFile->addError($error, $stackPtr, 'Found', $data);
    }
}
<!-- カスタムスニフ読み込み設定 -->
<?xml version="1.0"?>
<ruleset name="Custom Standards">
    <description>独自コーディング規約</description>

    <!-- カスタムスニフディレクトリ -->
    <config name="installed_paths" value="./CustomSniffs"/>

    <!-- 基本規約 -->
    <rule ref="PSR12"/>

    <!-- カスタムルール -->
    <rule ref="CustomSniffs.Functions.ForbiddenFunctions">
        <properties>
            <property name="forbiddenFunctions" type="array">
                <element key="eval" value="危険な関数です"/>
                <element key="var_dump" value="デバッグ関数です"/>
            </property>
        </properties>
    </rule>
</ruleset>

高度な使用例とトラブルシューティング

# パフォーマンス最適化
./vendor/bin/phpcs --parallel=8 src/

# 特定エラーのみ表示
./vendor/bin/phpcs --severity=error src/

# 警告レベル以上のみ
./vendor/bin/phpcs --warning-severity=0 src/

# キャッシュ使用
./vendor/bin/phpcs --cache=.phpcs-cache src/

# デバッグ出力
./vendor/bin/phpcs -vvv src/User.php

# インストール済み標準確認
./vendor/bin/phpcs -i

# 特定ルールの詳細確認
./vendor/bin/phpcs --explain src/User.php

# 統計情報出力
./vendor/bin/phpcs --report=info src/

# git hooks統合
# .git/hooks/pre-commit
#!/bin/bash
FILES=$(git diff --cached --name-only --diff-filter=ACMR | grep '\.php$')
if [ -n "$FILES" ]; then
    ./vendor/bin/phpcs --standard=PSR12 $FILES
    if [ $? -ne 0 ]; then
        echo "PHP CodeSniffer found violations. Please fix and try again."
        exit 1
    fi
fi

# Makefile統合
.PHONY: phpcs phpcbf quality

phpcs:
	./vendor/bin/phpcs --standard=PSR12 src/ tests/

phpcbf:
	./vendor/bin/phpcbf --standard=PSR12 src/ tests/

quality: phpcs
	@echo "Code quality check completed"