oceanmoon/coding-standard

PHP_CodeSniffer coding standard extending PSR-12 with lowerCamelCase naming and modern PHP 8.4+ rules.

Maintainers

Package info

github.com/mossy2100/PHP-Coding-Standard

Type:phpcodesniffer-standard

pkg:composer/oceanmoon/coding-standard

Transparency log

Statistics

Installs: 14

Dependents: 5

Suggesters: 0

Stars: 0

Open Issues: 0

v2.1.0 2026-08-16 02:00 UTC

This package is auto-updated.

Last update: 2026-08-16 03:49:18 UTC


README

A PHP_CodeSniffer coding standard for PHP 8.4, developed by Shaun Moss.

License | Changelog

PHP 8.4

Description

This package provides a custom PHP_CodeSniffer coding standard for PHP, which extends PSR-12 with additional rules for consistent naming conventions and modern PHP 8.4+ syntax.

Key Features:

  • Extends PSR-12 coding standard.
  • Enforces "camelCase" naming for variables, parameters, and properties.
  • Enforces consistent array formatting: single-line, grid, one-per-line, and associative with aligned arrows.
  • Removes unnecessary parentheses around class instantiation (PHP 8.4+).
  • Enforces correct indentation for property hooks.
  • Automatic registration with PHP_CodeSniffer.

The package provides several custom sniffs to cover gaps in the available standards. These include:

  • OceanMoon.Arrays.ArrayDeclaration: Enforces consistent array formatting with lists and associative arrays.
  • OceanMoon.Classes.ClassInstantiationNoBrackets: Removes unnecessary parentheses around class instantiation when accessing members (PHP 8.4+).
  • OceanMoon.Classes.PropertyDeclaration: Verifies property declarations, with property hook support (PHP 8.4+).
  • OceanMoon.WhiteSpace.ScopeIndent: Checks that control structures and code are indented correctly, with property hook support (PHP 8.4+).
  • OceanMoon.PHP.DisallowMultiConstantDefinition: Disallows defining multiple constants in one statement. A fork of SlevomatCodingStandard.Classes.DisallowMultiConstantDefinition fixing a false positive on constants with a parenthesized multi-argument value (e.g. const I = new Complex(0, 1);).

See Custom Sniffs for details.

Development and Quality Assurance

Claude Chat and Claude Code were used in the development of this package. The core classes were designed, coded, and commented primarily by the author, with Claude providing substantial assistance with code review, suggesting improvements, debugging, and generating tests and documentation.

All code was thoroughly reviewed by the author, and validated using industry-standard tools including PHP_CodeSniffer and PHPStan (to level 9) to ensure full compliance with PSR-12 coding standards.

This collaborative approach has produced a well-designed, production-ready package with thorough test coverage and documentation.

Requirements

  • PHP ^8.4
  • squizlabs/php_codesniffer ^4.0
  • slevomat/coding-standard ^8.25
  • dealerdirect/phpcodesniffer-composer-installer ^1.0

Installation

composer require --dev oceanmoon/coding-standard

The standard is automatically registered with PHP_CodeSniffer via the dealerdirect/phpcodesniffer-composer-installer plugin.

Usage

Create a phpcs.xml file in your project root:

<?xml version="1.0"?>
<ruleset name="My Project">
    <description>Coding standard for my project</description>

    <file>src</file>
    <file>tests</file>

    <rule ref="OceanMoon"/>
</ruleset>

Then run:

vendor/bin/phpcs        # Check for issues
vendor/bin/phpcbf       # Auto-fix issues

Included Sniffs

The OceanMoon Coding Standard extends PSR-12, borrows from existing standards, and adds several custom sniffs.

  1. Inherited Sniffs - From PSR-12 and other standards.
  2. Custom Sniffs - Developed for this standard.

Variable and Property Naming Convention

This coding standard is supplied by the Squiz.NamingConventions.ValidVariableName sniff, which ensures all variables, parameters, and properties:

  1. Use the $camelCase style.
  2. Do not have leading underscores.

Good:

$userName = 'John';
$orderTotal = 100;
$isValid = true;

Bad:

$user_name = 'John';   // snake_case not allowed
$_private = 'value';   // leading underscore not allowed
$UserName = 'John';    // UpperCamelCase not allowed

So - why is this included?

PSR-12 and PER 3.0 do not mandate variable naming conventions. Specifically, from PSR-1, Section 4.2 "Properties":

This guide intentionally avoids any recommendation regarding the use of $StudlyCaps, $camelCase, or $under_score property names. Whatever naming convention is used SHOULD be applied consistently within a reasonable scope. That scope may be vendor-level, package-level, class-level, or method-level.

In addition, from PER Coding Style 3.0 Section 4.3 "Properties and Constants":

Property or constant names MUST NOT be prefixed with a single underscore to indicate protected or private visibility. That is, an underscore prefix explicitly has no meaning.

Once upon a time, the convention was to use $snake_case for variable names and properties; however, as the object-oriented features of PHP evolved, it became more common to use $camelCase, following the coding convention from Java. AI-generated code typically uses $camelCase, which is indicative of the trend. Therefore, given the requirement to be consistent, this sniff enforces the use of $camelCase for all variables, class properties, and function parameters.

Similarly, using an underscore prefix to indicate protected or private visibility was common practice in until PHP 5.0 when visibility modifiers became available. Now, the use of an underscore prefix is generally discouraged or disallowed.

This sniff is compliant with several PHP coding standards:

  1. Symfony requires $camelCase (ref).
  2. Laravel requires $camelCase (unofficially).
  3. Drupal variable names may use either $camelCase or $snake_case (ref), as long as consistency is maintained. Properties should use $camelCase, and protected or private properties should not use an underscore prefix. (ref).

WordPress is the main variation, requiring $snake_case for variables, but permitting either $snake_case or $camelCase for properties.

Yoda-style Comparisons

A Yoda condition puts the constant on the left of a comparison (true === $x instead of $x === true), so an accidental = when == was meant becomes a parse error instead of a silent, always-truthy assignment.

Opinion on Yoda conditions is split across the PHP ecosystem:

  1. Symfony requires them.
  2. WordPress required them too, but is phasing the requirement out. Modern WordPress core updates and sub-ecosystems like WooCommerce have largely voted to remove or forbid Yoda style, in favor of letting tooling catch accidental assignments directly (ref).
  3. Drupal explicitly disallows Yoda conditions, prioritizing left-to-right readability for developers scanning a condition. Its drupal/coder PHPCS ruleset enforces this via a DisallowYodaConditions sniff (ref).
  4. Laravel doesn't use Yoda style anywhere in its ecosystem, favoring expressive, natural-reading syntax over it. Laravel Pint (Laravel's code-style tool, a wrapper around PHP-CS-Fixer) actively rewrites Yoda expressions back to standard order via PHP-CS-Fixer's yoda_style rule, configured with equal/identical/less_and_greater all false.
  5. The Slevomat coding standard, which this standard borrows many rules from, expressly disallows Yoda-style comparisons as a less readable anti-pattern, via the DisallowYodaComparison sniff (not included here).
  6. Modern IDEs, such as PhpStorm and VS Code with the Intelephense extension, will flag an assignment inside a boolean expression (e.g. an if/while condition) directly, regardless of operand order.

Given that some PHP developers will use Yoda conditions and some won't, this coding standard is deliberately silent on the issue. Write comparisons in whichever order reads best to you.

It does, however, include the Generic.CodeAnalysis.AssignmentInCondition sniff, which flags assignments in if, elseif, while, for, switch, case, and match conditions/expressions. This directly addresses the problem Yoda-style comparisons are intended to solve, without dictating operand order.

License

MIT License - see LICENSE for details.

Support

For questions or suggestions, please open an issue.

Changelog

See CHANGELOG.md for version history and changes.