PHPackages                             knplabs/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. [Validation &amp; Sanitization](/categories/validation)
4. /
5. knplabs/phpstan-rules

ActivePhpstan-extension[Validation &amp; Sanitization](/categories/validation)

knplabs/phpstan-rules
=====================

PHPStan rules shared across KnpLabs organization projects

v0.1.0(1mo ago)1736↑100%[1 issues](https://github.com/KnpLabs/phpstan-rules/issues)[1 PRs](https://github.com/KnpLabs/phpstan-rules/pulls)MITPHPPHP ^8.2CI passing

Since Jul 15Pushed 1mo agoCompare

[ Source](https://github.com/KnpLabs/phpstan-rules)[ Packagist](https://packagist.org/packages/knplabs/phpstan-rules)[ Docs](https://github.com/KnpLabs/phpstan-rules)[ RSS](/packages/knplabs-phpstan-rules/feed)WikiDiscussions main Synced 1w ago

READMEChangelog (2)Dependencies (3)Versions (4)Used By (0)

knplabs/phpstan-rules
=====================

[](#knplabsphpstan-rules)

[![CI](https://github.com/KnpLabs/phpstan-rules/actions/workflows/ci.yml/badge.svg)](https://github.com/KnpLabs/phpstan-rules/actions/workflows/ci.yml)[![PHP](https://camo.githubusercontent.com/bca35c89cfe52417848aa53095ddc86fabc6b4f12a638f8b43625f53a4c11ef5/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f5048502d382e32253230253743253230382e33253230253743253230382e34253230253743253230382e352d626c7565)](https://www.php.net/)[![Packagist](https://camo.githubusercontent.com/ba6b31bfdb8f1b413a910c17374b2a1655009f6ba38a92db87a1a61436d22c90/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f762f6b6e706c6162732f7068707374616e2d72756c6573)](https://packagist.org/packages/knplabs/phpstan-rules)[![License](https://camo.githubusercontent.com/3ed24bcf1cd239a9ce002041701cf9476eef4cba138d78d17c1a93b07ede2dfc/68747470733a2f2f696d672e736869656c64732e696f2f6769746875622f6c6963656e73652f4b6e704c6162732f7068707374616e2d72756c6573)](LICENSE)

PHPStan rules shared across KnpLabs organization projects.

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

[](#requirements)

- PHP 8.2 or higher
- PHPStan ^2.0

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

[](#installation)

### Using phpstan/extension-installer (recommended)

[](#using-phpstanextension-installer-recommended)

```
composer require --dev knplabs/phpstan-rules phpstan/extension-installer
```

If you don't use `phpstan/extension-installer`, include the extension in your `phpstan.neon`:

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

Rules
-----

[](#rules)

### `clock.disallowDateTimeNow` — PSR-20 Clock Abstraction

[](#clockdisallowdatetimenow--psr-20-clock-abstraction)

Enforces the [PSR-20](https://www.php-fig.org/psr/psr-20/) recommendation to avoid instantiating `DateTime` or `DateTimeImmutable` with a relative or implicit date. This makes code that depends on the current time testable and respects the clock abstraction.

**Triggers on:**

```
$a = new DateTime();
$b = new DateTime('now');
$c = new DateTimeImmutable();
$d = new DateTimeImmutable('now');
$e = new DateTimeImmutable('yesterday');
$f = new DateTimeImmutable('tomorrow');
$g = new DateTime('+1 day');
$h = new DateTimeImmutable('next Monday');
```

**Does not trigger on** (absolute date strings and variables are allowed):

```
$a = new DateTime('2023-01-01');
$b = new DateTimeImmutable('2023-12-31 23:59:59');
$c = new DateTimeImmutable($dateVariable);
```

**Recommended fix:** inject `Psr\Clock\ClockInterface` and call `$clock->now()`:

```
use Psr\Clock\ClockInterface;

final class MyService
{
    public function __construct(private readonly ClockInterface $clock) {}

    public function doSomething(): void
    {
        $now = $this->clock->now();
        // ...
    }
}
```

### `clock.disallowTimeFunctions` — PSR-20 Clock Abstraction (functions)

[](#clockdisallowtimefunctions--psr-20-clock-abstraction-functions)

Enforces the [PSR-20](https://www.php-fig.org/psr/psr-20/) recommendation to avoid using `time()` or `date()` directly. This makes code that depends on the current time testable and respects the clock abstraction.

**Triggers on:**

```
$a = time();
$b = date('Y-m-d');
$c = date('Y-m-d', time());
$d = date('Y-m-d', 'now');
```

**Does not trigger on** (explicit non-"now" timestamps are fine):

```
$a = date('Y-m-d', 1672531200);
$b = date('Y-m-d', $someTimestamp);
```

**Recommended fix:** inject `Psr\Clock\ClockInterface` and call `$clock->now()`:

```
use Psr\Clock\ClockInterface;

final class MyService
{
    public function __construct(private readonly ClockInterface $clock) {}

    public function doSomething(): void
    {
        $now = $this->clock->now();
        // ...
    }
}
```

Contributing
------------

[](#contributing)

See [CONTRIBUTING.md](CONTRIBUTING.md) for the human contributor guide.

If you are working with an AI agent, refer to [AGENTS.md](AGENTS.md) — it contains the AI-facing instructions for this repository.

Release &amp; Publishing
------------------------

[](#release--publishing)

Releases are fully automated with [`release-please`](https://github.com/googleapis/release-please) and published to [Packagist](https://packagist.org/packages/knplabs/phpstan-rules) as soon as a GitHub release goes out.

### Prerequisites (one-time setup)

[](#prerequisites-one-time-setup)

1. **Register the package on Packagist** — submit the repository once at [packagist.org/packages/submit](https://packagist.org/packages/submit).
2. **Add repository secrets** — in GitHub → Settings → Secrets and variables → Actions, create two repository secrets:

    Secret nameValue`PACKAGIST_USERNAME`Your Packagist account username`PACKAGIST_API_TOKEN`An API token generated on your [Packagist profile page](https://packagist.org/profile/)

### How it works

[](#how-it-works)

1. **Every push to `main`** runs the `Release` workflow (`.github/workflows/release.yml`), which calls [`GoogleCloudPlatform/release-please-action`](https://github.com/GoogleCloudPlatform/release-please-action). It parses [Conventional Commits](https://www.conventionalcommits.org/) (`feat:`, `fix:`, `doc:`, etc.) since the last release and keeps a **release PR** up to date with the bumped version and generated `CHANGELOG.md` entry.
2. **Merging the release PR** makes release-please tag the repository and publish the corresponding GitHub release automatically — no manual "Draft a new release" step is needed anymore.
3. That GitHub release publish event triggers the `Publish` workflow, which notifies Packagist via its REST API.
4. The new version appears on Packagist within a few minutes.

> **Commit messages matter** — release-please only picks up a version bump when commits follow the Conventional Commits format. Non-conforming commits are ignored when computing the next version.

### Manual re-trigger

[](#manual-re-trigger)

If the `Publish` workflow fails or you need to re-sync Packagist without creating a new release:

1. Go to Actions → **Publish** → **Run workflow**.
2. Click **Run workflow** (no inputs required).

License
-------

[](#license)

MIT — see [LICENSE](LICENSE).

###  Health Score

37

—

LowBetter than 81% of packages

Maintenance72

Regular maintenance activity

Popularity21

Limited adoption so far

Community9

Small or concentrated contributor base

Maturity38

Early-stage or recently created project

 Bus Factor1

Top contributor holds 86.7% 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 ~0 days

Total

2

Last Release

46d ago

### Community

Maintainers

![](https://avatars.githubusercontent.com/u/202732?v=4)[KNP Labs](/maintainers/KnpLabs)[@KnpLabs](https://github.com/KnpLabs)

---

Top Contributors

[![clementvtrd](https://avatars.githubusercontent.com/u/84911237?v=4)](https://github.com/clementvtrd "clementvtrd (13 commits)")[![ErwannRousseau](https://avatars.githubusercontent.com/u/121185412?v=4)](https://github.com/ErwannRousseau "ErwannRousseau (1 commits)")[![github-actions[bot]](https://avatars.githubusercontent.com/in/15368?v=4)](https://github.com/github-actions[bot] "github-actions[bot] (1 commits)")

---

Tags

phpPHPStanstatic analysisrulesgood practice

###  Code Quality

TestsPHPUnit

Code StylePHP CS Fixer

### Embed Badge

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

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

###  Alternatives

[larastan/larastan

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

6.5k66.6M11.1k](/packages/larastan-larastan)[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.

5124.9M119](/packages/shipmonk-dead-code-detector)[phpstan/phpstan-doctrine

Doctrine extensions for PHPStan

67577.1M1.6k](/packages/phpstan-phpstan-doctrine)[staabm/phpstan-dba

2972.7M2](/packages/staabm-phpstan-dba)[orrison/meliorstan

Provides PHPStan rules for improved code quality by detecting code smells and possible issues. In addition to enforcing particular naming and code style conventions to reduce bike-shedding.

1924.4k7](/packages/orrison-meliorstan)

PHPackages © 2026

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