Thank you for your interest in contributing to knplabs/phpstan-rules.
- To request a new rule or ask for help: open an issue describing the rule you'd like to see, why it matters, and ideally an example of code it should catch.
- To submit a rule directly: open a pull request following the steps below. Include the motivation, the code pattern it targets, and any edge cases you considered.
Create src/Rules/<Namespace>/<RuleName>.php. Implement PHPStan\Rules\Rule<T> where T is the AST node type from PhpParser\Node that your rule inspects.
<?php
declare(strict_types=1);
namespace KnpLabs\PHPStan\Rules\<Namespace>;
use PhpParser\Node;
use PHPStan\Analyser\Scope;
use PHPStan\Rules\IdentifierRuleError;
use PHPStan\Rules\Rule;
use PHPStan\Rules\RuleErrorBuilder;
/** @implements Rule<Node\<NodeType>> */
final readonly class <RuleName> implements Rule
{
public function getNodeType(): string
{
return Node\<NodeType>::class;
}
/** @return list<IdentifierRuleError> */
public function processNode(Node $node, Scope $scope): array
{
// return [] if no violation, or a RuleErrorBuilder error otherwise
}
}Add the class as a service in extension.neon:
services:
-
class: KnpLabs\PHPStan\Rules\<Namespace>\<RuleName>
tags:
- phpstan.rules.ruleCreate tests/Rules/<Namespace>/<RuleName>Test.php:
<?php
declare(strict_types=1);
namespace KnpLabs\PHPStan\Rules\Tests\Rules\<Namespace>;
use KnpLabs\PHPStan\Rules\<Namespace>\<RuleName>;
use PHPStan\Rules\Rule;
use PHPStan\Testing\RuleTestCase;
/** @extends RuleTestCase<<RuleName>> */
final class <RuleName>Test extends RuleTestCase
{
protected function getRule(): Rule
{
return new <RuleName>();
}
public function testRule(): void
{
$this->analyse([__DIR__ . '/fixtures/<name>.php'], [
['Expected error message.', /* line */ 5],
]);
}
}Create tests/Rules/<Namespace>/fixtures/<name>.php with PHP code that both triggers and does not trigger the rule. Keep it minimal and clearly commented.
All commands run inside the PHP container:
# Run your single test file
docker compose run --rm php vendor/bin/phpunit tests/Rules/<Namespace>/<RuleName>Test.php
# Run the full suite
docker compose run --rm php composer test
# Run PHPStan on the extension itself
docker compose run --rm php composer phpstan
# Check code style
docker compose run --rm php composer cs-check
# Fix code style automatically
docker compose run --rm php composer cs-fixCI runs test, phpstan, and cs-check against PHP 8.2, 8.3, 8.4, and 8.5. All must pass before a PR can be merged.
If you are contributing via an AI coding agent, refer to AGENTS.md — it contains the machine-readable instructions for this repository.
This project follows PSR-12 enforced by php-cs-fixer. All source files must declare strict_types=1. Run composer cs-fix before pushing.