northrook / php-cs
Custom PHP Coding Standards for Northrook projects.
Requires
- php: >=8.4
- phpstan/phpstan: ^2.2
Requires (Dev)
- phpunit/phpunit: ^13.2
README
Shared formatting and static analysis configuration.
This package provides:
- dPrint formatting via a shared
dprint.json - PHPStan at level
9, with custom rules for native PHPDoc member contracts (@method,@property,@const) and@abstract
The conventions here prioritize ergonomics over PSR alignment.
Requirements
- PHP 8.4+
- Composer
- dPrint CLI (optional, for formatting)
- PHPStan
2.2+
Installation
composer require --dev northrook/php-cs
Quick start
Add the package, then run the setup script from your project root:
composer require --dev northrook/php-cs vendor/bin/php-cs-config.php composer update
The script copies the shared dprint.json, generates a project phpstan.neon, and updates composer.json:
require-devphpstan/phpstanscripts.phpstanvendor/bin/phpstan analyse
Pass --force to overwrite existing config files or refresh values that were already set.
PHPStan
The custom rules and the enforced level 9 live in the package's canonical extension.neon.
The setup script generates a thin project phpstan.neon that includes that extension.neon and declares the analysed paths:
includes: - vendor/northrook/php-cs/extension.neon parameters: paths: - src - tests
- the source directory (
src, falling back tophp) tests, when present
Add any project-specific overrides (paths, excludePaths, ignoreErrors, a different level) to that generated phpstan.neon.
Run PHPStan from the project root:
composer phpstan
dPrint
Install the dPrint CLI.
The setup script copies the shared config into the project.
Format PHP files:
dprint fmt
Custom PHPStan rules
Native PHPDoc member contracts
Declare members that implementing or extending types must provide, using standard PHPDoc tags.
Checked on concrete classes, and on interfaces themselves.
| Tag | Example |
|---|---|
@const |
@const STATUS_CODE or @const string STATUS_CODE |
@property |
@property string $name |
@method |
@method string run() or @method static static register() |
@property-read and @property-write are treated like @property.
Tags can specify modifiers (e.g. static on @method) and types.
Visibility is not part of standard @method / @property syntax and is not validated.
On concrete classes, mismatches are reported with stable identifiers (e.g. requiresMember.method.TypeMissing).
Unexpected-but-compatible modifiers/types produce ignorable warnings.
Requirements are collected from the class's parents, interfaces, and traits.
/** * @method static static register() */ abstract class ContractSingleton { final protected static function getInstance(): static { return self::$instance ??= self::register(); } }
@abstract tag
Mark members on abstract classes or traits that every concrete descendant must redeclare.
abstract class Base { /** @abstract */ public const string LABEL = 'base'; /** @abstract */ protected string $name = 'base'; /** @abstract */ public function label(): string { return self::LABEL; } }
A concrete class must declare its own versions of these members, inheritance alone is not enough.
Sealed trait methods
Errors when a class, trait, or enum body redeclares a final method inherited from a directly-used trait.
PHP silently lets the using type override a trait's final method, defeating the intended seal (PHP only fatals when a subclass overrides an inherited final trait method).
trait Sealed { final public function run(): string { return 'sealed'; } } final class Broken { use Sealed; // finalTraitMethod.overridden public function run(): string { return 'overridden'; } }
Reported with the finalTraitMethod.overridden identifier.
PhpStorm
The package ships .phpstorm.meta.php.
PhpStorm recognizes @const and @abstract in docblocks (in addition to the built-in @method and @property support).
Validation
In this repository:
composer check # phpstan + phpunit composer phpstan composer test