PHPStan rules shared across KnpLabs organization projects.
- PHP 8.2 or higher
- PHPStan ^2.0
composer require --dev knplabs/phpstan-rules phpstan/extension-installerIf you don't use phpstan/extension-installer, include the extension in your phpstan.neon:
includes:
- vendor/knplabs/phpstan-rules/extension.neonEnforces 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();
// ...
}
}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();
// ...
}
}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.
Releases are fully automated with release-please and published to Packagist as soon as a GitHub release goes out.
-
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
- Every push to
mainruns theReleaseworkflow (.github/workflows/release.yml), which callsGoogleCloudPlatform/release-please-action. It parses Conventional Commits (feat:,fix:,doc:, etc.) since the last release and keeps a release PR up to date with the bumped version and generatedCHANGELOG.mdentry. - 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.
- That GitHub release publish event triggers the
Publishworkflow, which notifies Packagist via its REST API. - 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.
If the Publish workflow fails or you need to re-sync Packagist without creating a new release:
- Go to Actions → Publish → Run workflow.
- Click Run workflow (no inputs required).
MIT — see LICENSE.