knplabs / phpstan-rules
PHPStan rules shared across KnpLabs organization projects
Package info
github.com/KnpLabs/phpstan-rules
Type:phpstan-extension
pkg:composer/knplabs/phpstan-rules
Requires
- php: ^8.2
- phpstan/phpstan: ^2.0
Requires (Dev)
- friendsofphp/php-cs-fixer: ^3.0
- phpunit/phpunit: ^11.0
Suggests
- phpstan/extension-installer: For automatic extension loading
This package is auto-updated.
Last update: 2026-07-15 15:52:12 UTC
README
PHPStan rules shared across KnpLabs organization projects.
Requirements
- PHP 8.2 or higher
- PHPStan ^2.0
Installation
Using phpstan/extension-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
clock.disallowDateTimeNow — PSR-20 Clock Abstraction
Enforces the PSR-20 recommendation to avoid instantiating DateTime or DateTimeImmutable with the current time directly. 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');
Does not trigger on (explicit non-"now" timestamps are fine):
$a = new DateTime('2023-01-01'); $b = new DateTimeImmutable('yesterday');
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)
Enforces the 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
See CONTRIBUTING.md for the human contributor guide.
If you are working with an AI agent, refer to AGENTS.md — it contains the AI-facing instructions for this repository.
Release & Publishing
Releases are published to Packagist automatically when a GitHub release is created.
Prerequisites (one-time setup)
-
Register the package on Packagist — submit the repository once at packagist.org/packages/submit.
-
Add repository secrets — in GitHub → Settings → Secrets and variables → Actions, create two repository secrets:
Secret name Value PACKAGIST_USERNAMEYour Packagist account username PACKAGIST_API_TOKENAn API token generated on your Packagist profile page
Publishing a release
- Create a new release in GitHub (Releases → Draft a new release).
- Set the tag (e.g.
v1.2.0), fill in the title and description, then click Publish release. - The
Publishworkflow triggers automatically and notifies Packagist via its REST API. - The new version appears on Packagist within a few minutes.
Draft and pre-releases — the workflow only fires on published releases. Saving a draft or marking a release as a pre-release does not trigger the automation.
Manual re-trigger
If the workflow fails or you need to re-sync without creating a new release:
- Go to Actions → Publish → Run workflow.
- Click Run workflow (no inputs required).
License
MIT — see LICENSE.