This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
This is a PHP_CodeSniffer (PHPCS) standard package (drevops/phpcs-standard) that enforces custom coding conventions, specifically focused on configurable naming (snakeCase or camelCase) for local variables and parameters.
Key Goals:
- Enforce consistent naming conventions for local variables and function/method parameters
- Support configurable formats: snakeCase (default) or camelCase
- Exclude class properties from naming enforcement (properties follow different conventions)
- Preserve inherited parameter names from interfaces and parent classes
- Provide auto-fixing support via
phpcbf - Provide a standalone, reusable PHPCS standard for the DrevOps ecosystem
composer installRuns PHPCS, PHPStan, and Rector in dry-run mode:
composer lintFix auto-fixable issues with PHPCBF and Rector:
composer lint-fixRun tests without coverage:
composer testRun tests with coverage (generates HTML and Cobertura reports in .logs/):
composer test-coverageCoverage reports are generated in:
- HTML:
.logs/.coverage-html/index.html - Cobertura XML:
.logs/cobertura.xml
Run a single test file:
./vendor/bin/phpunit tests/Unit/AbstractVariableSnakeCaseSniffTest.php
./vendor/bin/phpunit tests/Unit/LocalVariableNamingSniffTest.php
./vendor/bin/phpunit tests/Unit/ParameterNamingSniffTest.phpRun only unit tests or functional tests:
./vendor/bin/phpunit tests/Unit/
./vendor/bin/phpunit tests/Functional/Run a specific test method:
./vendor/bin/phpunit --filter testMethodNameUpdate test fixtures (when tests fail due to expected output changes):
UPDATE_FIXTURES=1 ./vendor/bin/phpunitReset dependencies:
composer resetValidate composer.json:
composer validate
composer normalize --dry-runsrc/DrevOps/- Source code for the PHPCS standardSniffs/NamingConventions/AbstractVariableNamingSniff.php- Base class with shared functionalityLocalVariableNamingSniff.php- Enforces snake_case for local variablesParameterNamingSniff.php- Enforces snake_case for parameters
ruleset.xml- DrevOps standard definition
tests/- PHPUnit tests organized by type:Unit/- Unit tests for individual sniff methods (using reflection)AbstractVariableSnakeCaseSniffTest.php- Tests shared base class methodsLocalVariableNamingSniffTest.php- Tests local variable sniffParameterNamingSniffTest.php- Tests parameter sniffUnitTestCase.php- Base test class with helper methods
Functional/- Integration tests that run actual phpcs commandsFixtures/- Test fixture files with intentional violations
.github/workflows/- CI/CD pipelinesphpcs.xml- Project's own PHPCS configuration (based on Drupal standard)
The standard uses an abstract base class pattern with two concrete implementations:
Base class (src/DrevOps/Sniffs/NamingConventions/AbstractVariableNamingSniff.php) containing shared functionality:
Public property:
$format- Configurable naming convention ('snakeCase' or 'camelCase', default: 'snakeCase')
Core methods:
register()- Registers T_VARIABLE token for processingisReserved()- Identifies PHP reserved variables ($this, $_GET, etc.)isSnakeCase()- Validates snake_case format using regexisCamelCase()- Validates camelCase format using regexisValidFormat()- Validates variable name against configured formattoSnakeCase()- Converts variable name to snake_casetoCamelCase()- Converts variable name to camelCasetoFormat()- Converts variable name to the configured format
Helper methods:
getParameterNames()- Extracts parameter names from function signatureisInParameterList()- Checks if variable is in parameter listfindEnclosingFunction()- Finds the enclosing function/closure for a variableisPromotedProperty()- Detects promoted constructor propertiesisParameter()- Checks if variable is a function/method parameter (with flag for body usage)isProperty()- Distinguishes class properties from local variablesisInheritedParameter()- Detects parameters from interfaces/parent classes
Enforces configurable naming convention for local variables inside functions/methods.
What gets checked:
- ✅ Local variables inside function/method bodies
- ❌ Function/method parameters (handled by ParameterNaming)
- ❌ Class properties (not enforced)
- ❌ Reserved PHP variables ($this, superglobals, etc.)
Error codes:
DrevOps.NamingConventions.LocalVariableNaming.NotSnakeCase(when format='snakeCase')DrevOps.NamingConventions.LocalVariableNaming.NotCamelCase(when format='camelCase')
Enforces configurable naming convention for function/method parameters.
What gets checked:
- ✅ Function and method parameters (in signature only)
- ❌ Local variables (handled by LocalVariableNaming)
- ❌ Parameters inherited from interfaces/parent classes/abstract methods
- ❌ Promoted constructor properties
Error codes:
DrevOps.NamingConventions.ParameterNaming.NotSnakeCase(when format='snakeCase')DrevOps.NamingConventions.ParameterNaming.NotCamelCase(when format='camelCase')
The standard is automatically registered via:
composer.jsondeclarestype: "phpcodesniffer-standard"extra.phpcodesniffer-standardspecifies the standard name:"DrevOps"dealerdirect/phpcodesniffer-composer-installerplugin handles registration- Standard definition in
src/DrevOps/ruleset.xmlreferences the sniff
Verify installation with: vendor/bin/phpcs -i (should list "DrevOps")
This project uses two complementary testing approaches:
Tests are organized by class hierarchy:
AbstractVariableSnakeCaseSniffTest.php
- Tests all shared base class methods using reflection
- Tests:
isSnakeCase(),toSnakeCase(),isReserved(),register(),getParameterNames(),isProperty(),isPromotedProperty(),isInheritedParameter() - Each test uses concrete sniff instances (LocalVariableNamingSniff or ParameterNamingSniff) to access protected methods
LocalVariableNamingSniffTest.php
- Tests sniff-specific logic: error code constant and
process()method - Configured to run only LocalVariableNaming sniff in isolation
- Validates that local variables are checked and parameters are skipped
ParameterNamingSniffTest.php
- Tests sniff-specific logic: error code constant,
register(), andprocess()method - Configured to run only ParameterNaming sniff in isolation
- Validates that parameters are checked and local variables are skipped
- Includes tests for inherited parameter detection
Key testing patterns:
- Use PHP reflection to test protected methods
- Use
processCode()helper to simulate PHPCS token processing - Use
findVariableToken()andfindFunctionToken()helpers to locate tokens - Each concrete sniff test overrides
setUp()to configure specific sniff isolation
LocalVariableNamingSniffFunctionalTest.php
- Run actual
phpcscommands as external processes - Test complete PHPCS integration with JSON output parsing
- Verify LocalVariableNaming sniff detection and error codes
ParameterNamingSniffFunctionalTest.php
- Run actual
phpcscommands as external processes - Test complete PHPCS integration with JSON output parsing
- Verify ParameterNaming sniff detection and error codes
Tests include:
- Confirms violations are detected with correct error codes
- Confirms correct exclusions (properties, inherited parameters, etc.)
- Validates clean code passes without errors
Test fixtures:
tests/Fixtures/VariableNaming.php- Contains intentional violationstests/Fixtures/InheritedParameters.php- Tests interface/parent class scenariostests/Fixtures/Valid.php- Clean code for positive testing- Fixtures are excluded from linting in
phpcs.xmlandrector.php
Coverage:
- Line coverage: 100% (158/158 lines covered)
- Reports:
.logs/.coverage-html/index.htmland.logs/cobertura.xml
- PHPCS - Code style checking (Drupal standard + strict types)
- Project's
phpcs.xmluses Drupal base +Generic.PHP.RequireStrictTypes - Relaxes array line length and function comment rules for test files
- Project's
- PHPStan (Level 9) - Static analysis with strict type checking
- Rector - Automated refactoring and code modernization targeting PHP 8.3+
- PHPUnit 11 - Testing framework with coverage reporting
- PHP Version: Requires PHP 8.3+ (composer.json)
- Namespace:
DrevOps\for sniff classes,DrevOps\PhpcsStandard\Tests\for tests - Autoloading: PSR-4 autoloading for both source and tests
- Strict Types: All PHP files must declare
strict_types=1 - Standard Name: "DrevOps" (registered via composer plugin)
- Test Coverage: Reports generated in
.logs/.coverage-html/and.logs/cobertura.xml
When implementing or modifying sniffs:
- Place sniff classes in
src/DrevOps/Sniffs/following PHPCS naming conventions- Format:
CategoryName/SniffNameSniff.php - Example:
NamingConventions/LocalVariableNamingSniff.php
- Format:
- Consider using abstract base classes for shared functionality across related sniffs
- Implement the
Sniffinterface fromPHP_CodeSniffer\Sniffs\Sniff - Use
declare(strict_types=1);at the top of all PHP files - Register tokens in
register()method (return array of T_* constants) - Process tokens in
process(File $phpcsFile, $stackPtr)method - Use
addFixableError()for violations that can be auto-fixed with phpcbf - Mark auto-fix code blocks with
@codeCoverageIgnore(not testable in unit tests) - Create both unit tests and functional tests:
- Unit tests for internal method logic using reflection
- Functional tests for complete PHPCS integration
- Organize tests by class hierarchy (abstract base tests separate from concrete tests)
- Create fixture files in
tests/Fixtures/with intentional violations - Follow error code naming:
StandardName.Category.SniffName.ErrorName- Examples:
DrevOps.NamingConventions.LocalVariableNaming.NotSnakeCaseDrevOps.NamingConventions.LocalVariableNaming.NotCamelCaseDrevOps.NamingConventions.ParameterNaming.NotSnakeCaseDrevOps.NamingConventions.ParameterNaming.NotCamelCase
- Examples:
GitHub Actions workflow (test-php.yml) runs on:
- Push to
mainbranch - Pull requests to
mainorfeature/**branches - Manual workflow dispatch (with optional terminal session for debugging)
Tests run across PHP versions: 8.3, 8.4, 8.5 (with --ignore-platform-reqs for 8.5)
Workflow steps:
- Composer validation and normalization check
- Code standards check (
composer lint) - can continue on error viaCI_LINT_IGNORE_FAILUREvariable - Tests with coverage (
composer test-coverage) - Upload coverage artifacts
- Upload results to Codecov (test results + coverage reports)
- Use snake_case for local variables and method parameters
- Use camelCase for method names and class properties
- Strict types declaration required in all files:
declare(strict_types=1); - Follow Drupal coding standards with added strict type requirements
- Single quotes for strings (double quotes when containing single quotes)
- Files must end with a newline character