PHPackages                             northrook/php-cs - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. [Utility &amp; Helpers](/categories/utility)
4. /
5. northrook/php-cs

ActiveLibrary[Utility &amp; Helpers](/categories/utility)

northrook/php-cs
================

Custom PHP Coding Standards for Northrook projects.

0.8.4(2w ago)03021BSD-3-ClausePHPPHP &gt;=8.4

Since May 13Pushed 2w agoCompare

[ Source](https://github.com/northrook/php-cs)[ Packagist](https://packagist.org/packages/northrook/php-cs)[ RSS](/packages/northrook-php-cs/feed)WikiDiscussions main Synced 2w ago

READMEChangelogDependencies (6)Versions (9)Used By (1)

PHP Coding Standards for Northrook projects
===========================================

[](#php-coding-standards-for-northrook-projects)

Shared formatting and static analysis configuration.

This package provides:

- **[dPrint](https://dprint.dev/)** formatting via a shared `dprint.json`
- **[PHPStan](https://phpstan.org/)** at level `9`, with custom rules for native PHPDoc member contracts (`@method`, `@property`, `@const`), `@abstract`, `@static`, `@singleton`, and sealed trait methods

The conventions here prioritize ergonomics over PSR alignment.

Requirements
------------

[](#requirements)

- PHP 8.4+
- [Composer](https://getcomposer.org/)
- [dPrint CLI](https://dprint.dev/install/) (optional, for formatting)
- [PHPStan](https://phpstan.org/) `2.2+`

Installation
------------

[](#installation)

```
composer require --dev northrook/php-cs
```

Quick start
-----------

[](#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
composer update
```

The script copies the shared `dprint.json`, generates a project `phpstan.neon`, and updates `composer.json`:

- `require-dev` `phpstan/phpstan`
- `scripts.phpstan` `vendor/bin/phpstan analyse`
- `scripts.php-cs-config` `vendor/bin/php-cs-config`
- `scripts.collision` `vendor/bin/collision-check`

After setup, these run as Composer scripts from the project root:

```
composer php-cs-config
composer collision
composer phpstan
```

Pass `--force` to overwrite existing config files or refresh values that were already set.

### PHPStan

[](#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 to `php`)
- `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

[](#dprint)

Install the [dPrint CLI](https://dprint.dev/install/).

The setup script copies the shared config into the project.

Format PHP files:

```
dprint fmt
```

Custom PHPStan rules
--------------------

[](#custom-phpstan-rules)

### Native PHPDoc member contracts

[](#native-phpdoc-member-contracts)

Declare members that implementing or extending types must provide, using standard PHPDoc tags.

Checked on **concrete classes**. On **interfaces**, only `@method` and `@const` must be declared natively — `@property*` is an implementor contract enforced on concrete classes.

TagExample`@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` for implementors.

`@method` can require `static`. Types are checked for `@method`, `@property`, and `@const`.

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 itself, its parents, interfaces, and traits — including nested traits and traits used by parents.

```
/**
 * @method static static register()
 */
abstract class ContractSingleton
{
    final protected static function getInstance(): static
    {
        return self::$instance ??= self::register();
    }
}
```

### `@abstract` tag

[](#abstract-tag)

Mark members on abstract classes or traits that every descendant must redeclare — including intermediate abstract classes.

```
abstract class Base
{
    /** @abstract */
    public const string LABEL = 'base';

    /** @abstract */
    protected string $name = 'base';

    /** @abstract */
    public function label(): string
    {
        return self::LABEL;
    }
}
```

Each class in the hierarchy must declare its own versions of these members; inheritance alone is not enough.

### `@static` tag

[](#static-tag)

Mark a class (or trait) as a static utility type: it must have a **non-public** constructor (`private` or `protected`). `final` is not required.

```
/**
 * @static
 */
class Hash
{
    private function __construct() {}

    public static function checksum(string $value): string { /* ... */ }
}
```

Subclasses must follow the same constructor rule. A `@static` trait imposes the rule on every class that uses it — including via nested traits or parents that use the trait.

Reported with the `staticClass.publicConstructor` identifier.

### `@singleton` tag

[](#singleton-tag)

Mark a class as a singleton façade. It must implement `\Northrook\Contracts\Interfaces\SingletonInterface`. This is intentionally only an interface check — extending `Northrook\Contracts\Singleton` is the usual way to satisfy the pattern, but is not required by the rule.

```
/**
 * @singleton
 */
final class Debug extends Singleton
{
    // ...
}
```

Reported with the `singleton.missingInterface` identifier.

### Sealed trait methods

[](#sealed-trait-methods)

Errors when a class, trait, or enum body redeclares a `final` method sealed by a trait — including traits used by parents and nested traits.

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.

Overrides in test directories are allowed by default. Configure path segments via `finalTraitMethod.testDirectories` (defaults to `tests`):

```
parameters:
	finalTraitMethod:
		testDirectories:
			- tests
			- fixtures
```

Set `testDirectories` to an empty list to enforce the seal everywhere.

PhpStorm
--------

[](#phpstorm)

The package ships `.phpstorm.meta.php`.

PhpStorm recognizes `@const`, `@abstract`, `@static`, and `@singleton` in docblocks (in addition to the built-in `@method` and `@property` support).

Validation
----------

[](#validation)

In this repository:

```
composer check   # phpstan + phpunit + collision
composer phpstan
composer test
composer collision
```

License
-------

[](#license)

[BSD-3-Clause](LICENSE)

###  Health Score

45

—

FairBetter than 91% of packages

Maintenance96

Actively maintained with recent releases

Popularity15

Limited adoption so far

Community8

Small or concentrated contributor base

Maturity51

Maturing project, gaining track record

 Bus Factor1

Top contributor holds 100% of commits — single point of failure

How is this calculated?**Maintenance (25%)** — Last commit recency, latest release date, and issue-to-star ratio. Uses a 2-year decay window.

**Popularity (30%)** — Total and monthly downloads, GitHub stars, and forks. Logarithmic scaling prevents top-heavy scores.

**Community (15%)** — Contributors, dependents, forks, watchers, and maintainers. Measures real ecosystem engagement.

**Maturity (30%)** — Project age, version count, PHP version support, and release stability.

###  Release Activity

Cadence

Every ~63 days

Recently: every ~5 days

Total

8

Last Release

18d ago

PHP version history (2 changes)0.5.0PHP &gt;=8.2

0.7.0PHP &gt;=8.4

### Community

Maintainers

![](https://avatars.githubusercontent.com/u/60818044?v=4)[Martin](/maintainers/martinlikescoffee)[@martinlikescoffee](https://github.com/martinlikescoffee)

---

Top Contributors

[![martinlikescoffee](https://avatars.githubusercontent.com/u/60818044?v=4)](https://github.com/martinlikescoffee "martinlikescoffee (44 commits)")

---

Tags

internalphpphp-cs-fixerwipdev

###  Code Quality

TestsPHPUnit

### Embed Badge

![Health badge](/badges/northrook-php-cs/health.svg)

```
[![Health](https://phpackages.com/badges/northrook-php-cs/health.svg)](https://phpackages.com/packages/northrook-php-cs)
```

###  Alternatives

[rector/rector

Instant Upgrade and Automated Refactoring of any PHP code

10.4k145.3M11.5k](/packages/rector-rector)[deptrac/deptrac

Deptrac is a static code analysis tool that helps to enforce rules for dependencies between software layers.

3.0k9.8M261](/packages/deptrac-deptrac)[ergebnis/php-cs-fixer-config

Provides a configuration factory and rule set factories for friendsofphp/php-cs-fixer.

703.1M216](/packages/ergebnis-php-cs-fixer-config)[ssch/typo3-rector

Instant fixes for your TYPO3 PHP code by using Rector.

2613.3M489](/packages/ssch-typo3-rector)[ticketswap/phpstan-error-formatter

A minimalistic error formatter for PHPStan

87766.6k61](/packages/ticketswap-phpstan-error-formatter)[ergebnis/rector-rules

Provides rules for rector/rector.

10264.7k56](/packages/ergebnis-rector-rules)

PHPackages © 2026

[Directory](/)[Categories](/categories)[Trending](/trending)[Changelog](/changelog)[Analyze](/analyze)
