PHPackages                             nijidigital/phpstan-rules - 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. [Testing &amp; Quality](/categories/testing)
4. /
5. nijidigital/phpstan-rules

ActivePhpstan-extension[Testing &amp; Quality](/categories/testing)

nijidigital/phpstan-rules
=========================

custom phpstan rules created by dsf-niji

v2.1.1(9mo ago)0919↑39.3%1[1 issues](https://github.com/NijiDigital/phpstan-rules/issues)MITPHPPHP &gt;=8.2

Since Sep 5Pushed 9mo ago1 watchersCompare

[ Source](https://github.com/NijiDigital/phpstan-rules)[ Packagist](https://packagist.org/packages/nijidigital/phpstan-rules)[ Docs](https://github.com/NijiDigital/phpstan-rules)[ RSS](/packages/nijidigital-phpstan-rules/feed)WikiDiscussions v1.x Synced 2d ago

READMEChangelog (6)Dependencies (7)Versions (8)Used By (0)

nijidigital/phpstan-rules
=========================

[](#nijidigitalphpstan-rules)

Custom PhpStan rules made with ❤️ by [Niji](https://www.niji.fr).

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

[](#installation)

To use this extension, require it in [Composer](https://getcomposer.org/):

```
composer require --dev nijidigital/phpstan-rules
```

If you also install [phpstan/extension-installer](https://github.com/phpstan/extension-installer) then you're all set!

 Manual installationIf you don't want to use `phpstan/extension-installer`, include extension.neon in your project's PHPStan config:

```
includes:
    - vendor/nijidigital/phpstan-rules/extension.neon

```

Existing rules
--------------

[](#existing-rules)

### `NoRelativeDatetime`

[](#norelativedatetime)

Prevents usage of relative date/time strings and empty constructors in `DateTime` and `DateTimeImmutable` to ensure consistent and testable date handling.

#### Examples

[](#examples)

❌ **Invalid:**

```
// Empty constructors
$now = new \DateTime();
$now = new \DateTimeImmutable();

// Relative date strings
$yesterday = new \DateTime('yesterday');
$nextMonth = new \DateTime('next month');
$twoHoursLater = new \DateTimeImmutable('+2 hours');
```

✅ **Valid alternatives:**

```
// Use absolute dates for fixed dates
$fixedDate = new \DateTime('2025-07-01 13:12:11');

// Use ClockInterface for current time and modifications
function doSomethingWithTime(ClockInterface $clock) {
    $now = $clock->now();
    $yesterday = $clock->now()->modify('-1 day');
    $nextMonth = $clock->now()->modify('+1 month');

    // (...)
}
```

### `DoctrineMigrationsSafeMigration`

[](#doctrinemigrationssafemigration)

Detects potentially unsafe database migration operations that could break backward compatibility in Doctrine migrations. Operations can be marked as safe using PHPStan's standard `@phpstan-ignore` comment.

#### Examples

[](#examples-1)

❌ **Invalid:**

```
class UnsafeMigration extends AbstractMigration
{
    public function up(Schema $schema): void
    {
        // These operations may not be backward compatible
        $this->addSql('DROP TABLE user');
        $this->addSql('ALTER TABLE user CHANGE name email VARCHAR(255)');
        $this->addSql('ALTER TABLE user DROP COLUMN name');
        $this->addSql('DROP DATABASE test');
        $this->addSql('TRUNCATE TABLE user');
    }
}
```

✅ **Valid alternatives:**

```
class SafeMigration extends AbstractMigration
{
    public function up(Schema $schema): void
    {
        // Safe operations (no ignore comment needed)
        $this->addSql('ALTER TABLE user ADD COLUMN email VARCHAR(255)');
        $this->addSql('CREATE INDEX idx_user_email ON user (email)');
        $this->addSql('INSERT INTO user (name) VALUES (\'John\')');

        // Unsafe operations marked as intentionally safe
        /* @phpstan-ignore doctrineMigrations.unsafeMigration */
        $this->addSql('DROP TABLE legacy_user');

        /* @phpstan-ignore doctrineMigrations.unsafeMigration */
        $this->addSql('ALTER TABLE user CHANGE name full_name VARCHAR(255)');
    }
}
```

#### Configuration

[](#configuration)

You can customize the behavior of this rule using the `parameters` section in your `phpstan.neon` configuration:

```
parameters:
    niji:
        doctrineMigrations:
            safeMigration:
                # Custom list of blacklisted SQL patterns with their error messages
                blacklistedQueries:
                    '/DROP\s+TABLE\s+/im': 'Dropping tables is not allowed'
                    '/ALTER\s+TABLE\s+.+\s+DROP\s+COLUMN/im': 'Dropping columns breaks backward compatibility'
```

**Available options:**

- `blacklistedQueries`: Array of regex patterns (as keys) with their corresponding error messages (as values). If not specified, uses default patterns for common unsafe operations.

### `DoctrineMigrationsDescription`

[](#doctrinemigrationsdescription)

Ensures that Doctrine migration classes provide meaningful descriptions by validating the return value of the `getDescription()` method against a configurable pattern.

#### Examples

[](#examples-2)

❌ **Invalid:**

```
class MyMigration extends AbstractMigration
{
    public function getDescription(): string
    {
        return ''; // Empty description
    }

    public function up(Schema $schema): void
    {
        $this->addSql('ALTER TABLE user ADD COLUMN email VARCHAR(255)');
    }
}
```

✅ **Valid:**

```
class MyMigration extends AbstractMigration
{
    public function getDescription(): string
    {
        return 'Add email column to user table';
    }

    public function up(Schema $schema): void
    {
        $this->addSql('ALTER TABLE user ADD COLUMN email VARCHAR(255)');
    }
}
```

#### Configuration

[](#configuration-1)

By default, the rule accepts any non-empty string. You can customize the accepted pattern using the `parameters` section in your `phpstan.neon` configuration:

```
parameters:
    niji:
        doctrineMigrations:
            description:
                # Custom regex pattern for migration descriptions
                acceptedPattern: '/^[A-Z][a-z0-9\s]+\.?$/'
```

**Available options:**

- `acceptedPattern`: A regex pattern that migration descriptions must match. Defaults to `/.+/im` (any non-empty string).

Troubleshooting
---------------

[](#troubleshooting)

### PhpStorm doesn't provide any autocomplete on PhpStan classes

[](#phpstorm-doesnt-provide-any-autocomplete-on-phpstan-classes)

Details Taken from \[this blog\]([https://blog.bitexpert.de/blog/phpstorm\_phpstan\_wsl2\_issue](https://blog.bitexpert.de/blog/phpstorm_phpstan_wsl2_issue)) : ```
1. Copy the file `vendor/phpstan/phpstan/phpstan.phar` to a local folder of your choice, ie : `C:\php_include_path`.
2. In PhpStorm, go to File | Settings | PHP and add your newly created folder to the include path.

```

###  Health Score

38

—

LowBetter than 83% of packages

Maintenance58

Moderate activity, may be stable

Popularity18

Limited adoption so far

Community13

Small or concentrated contributor base

Maturity53

Maturing project, gaining track record

 Bus Factor2

2 contributors hold 50%+ of commits

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 ~4 days

Total

8

Last Release

275d ago

Major Versions

v1.0.0 → v2.0.02025-09-08

v1.1.0 → v2.1.02025-10-02

v1.x-dev → v2.1.12025-10-02

### Community

Maintainers

![](https://avatars.githubusercontent.com/u/58166712?v=4)[Morgan NEUTE](/maintainers/niji-mneute)[@niji-mneute](https://github.com/niji-mneute)

![](https://avatars.githubusercontent.com/u/33158021?v=4)[alexandre HUBERT](/maintainers/niji-ahubert)[@niji-ahubert](https://github.com/niji-ahubert)

---

Top Contributors

[![niji-ahubert](https://avatars.githubusercontent.com/u/33158021?v=4)](https://github.com/niji-ahubert "niji-ahubert (5 commits)")[![niji-vlebiannic](https://avatars.githubusercontent.com/u/47846817?v=4)](https://github.com/niji-vlebiannic "niji-vlebiannic (4 commits)")[![niji-mneute](https://avatars.githubusercontent.com/u/58166712?v=4)](https://github.com/niji-mneute "niji-mneute (3 commits)")

###  Code Quality

TestsPHPUnit

Static AnalysisRector

Code StylePHP CS Fixer

### Embed Badge

![Health badge](/badges/nijidigital-phpstan-rules/health.svg)

```
[![Health](https://phpackages.com/badges/nijidigital-phpstan-rules/health.svg)](https://phpackages.com/packages/nijidigital-phpstan-rules)
```

###  Alternatives

[larastan/larastan

Larastan - Discover bugs in your code without running it. A phpstan/phpstan extension for Laravel

6.5k55.4M8.4k](/packages/larastan-larastan)[phpstan/phpstan-symfony

Symfony Framework extensions and rules for PHPStan

79475.7M2.2k](/packages/phpstan-phpstan-symfony)[phpstan/phpstan-doctrine

Doctrine extensions for PHPStan

67272.8M1.4k](/packages/phpstan-phpstan-doctrine)[shipmonk/dead-code-detector

Dead code detector to find unused PHP code via PHPStan extension. Can automatically remove dead PHP code. Supports libraries like Symfony, Doctrine, PHPUnit etc. Detects dead cycles. Can detect dead code that is tested.

4853.5M91](/packages/shipmonk-dead-code-detector)[tempest/framework

The PHP framework that gets out of your way.

2.2k34.4k15](/packages/tempest-framework)[tomasvotruba/cognitive-complexity

PHPStan rules to measure cognitive complexity of your classes and methods

1635.6M288](/packages/tomasvotruba-cognitive-complexity)

PHPackages © 2026

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