A collection of custom PHPStan rules that enforce coding standards and improve code quality in PHP projects. This extension provides additional static analysis rules focused on naming conventions, annotations, and PHPDoc consistency.
This package includes three powerful rules that help maintain high code quality:
Rule: CommandClassShouldBeHelpCommandHandlerClass
Enforces that classes ending with "Command" must have a @see
PHPDoc tag pointing to their corresponding CommandHandler class.
Example:
/**
* @see CreateUserCommandHandler
*/
class CreateUserCommand
{
// Command implementation
}
Exception: Classes with an __invoke
method are exempt from this rule.
Rule: EventListenerClassShouldBeIncludeAsListenerAttribute
Ensures that classes ending with "EventListener" are properly annotated with the #[AsEventListener]
attribute.
Example:
use Symfony\Component\EventDispatcher\Attribute\AsEventListener;
#[AsEventListener]
class UserRegisteredEventListener
{
// Event listener implementation
}
Rule: NotShouldPhpdocReturnIfExistTypeHint
Prevents redundant or conflicting @return
PHPDoc annotations when native return type hints are already declared.
Good:
public function getUser(): User
{
return $this->user;
}
Bad:
/**
* @return User
*/
public function getUser(): User // Redundant @return annotation
{
return $this->user;
}
- PHP: >8.3
- PHPStan: ^2.0
- PHPStan PHPDoc Parser: ^2.2
Install the package as a development dependency:
composer require --dev simtel/phpstan-rules
Add the bundled configuration to your phpstan.neon
or phpstan.dist.neon
:
includes:
- vendor/simtel/phpstan-rules/rules.neon
For granular control, register specific rules:
parameters:
rules:
- Simtel\PHPStanRules\Rule\CommandClassShouldBeHelpCommandHandlerClass
- Simtel\PHPStanRules\Rule\EventListenerClassShouldBeIncludeAsListenerAttribute
- Simtel\PHPStanRules\Rule\NotShouldPhpdocReturnIfExistTypeHint
includes:
- vendor/simtel/phpstan-rules/rules.neon
parameters:
level: 8
paths:
- src/
excludePaths:
- tests/
ignoreErrors:
# Exclude specific patterns if needed
- '#Command class should be include phpDoc with @see attribute#'
path: src/Deprecated/
-
Clone the repository:
git clone <repository-url> phpstan-rules cd phpstan-rules
-
Install dependencies:
composer install
# Run all tests
vendor/bin/phpunit
# Run specific test class
vendor/bin/phpunit tests/Rules/CommandClassShouldBeHelpCommandHandlerClassTest.php
# Check coding standards
vendor/bin/ecs check
# Fix coding standards automatically
vendor/bin/ecs fix
# Run PHPStan on the project itself
vendor/bin/phpstan analyse
.
βββ src/Rule/ # Rule implementations
β βββ CommandClassShouldBeHelpCommandHandlerClass.php
β βββ EventListenerClassShouldBeIncludeAsListenerAttribute.php
β βββ NotShouldPhpdocReturnIfExistTypeHint.php
βββ tests/
β βββ Fixture/ # Test code samples
β β βββ EventListener/
β β βββ Return/
β βββ Rules/ # Unit tests for rules
β βββ data/ # Additional test data
βββ composer.json # Package configuration
βββ ecs.php # ECS configuration
βββ README.md # This file
-
Implement the Rule Interface:
<?php namespace Simtel\PHPStanRules\Rule; use PHPStan\Rules\Rule; /** * @implements Rule<NodeType> */ final class YourNewRule implements Rule { public function getNodeType(): string { return NodeType::class; } public function processNode(Node $node, Scope $scope): array { // Rule implementation } }
-
Create Test Cases:
<?php namespace Simtel\PHPStanRules\Tests\Rules; use PHPStan\Rules\Rule; use PHPStan\Testing\RuleTestCase; class YourNewRuleTest extends RuleTestCase { protected function getRule(): Rule { return new YourNewRule(); } public function testValidCase(): void { $this->analyse([__DIR__ . '/../Fixture/Valid.php'], []); } }
-
Add Fixture Files: Create test PHP files in
tests/Fixture/
to validate rule behavior.
The project uses PHPUnit with PHPStan's RuleTestCase
base class:
- Fixture Files: Real PHP code examples in
tests/Fixture/
- Data Files: Additional test scenarios in
tests/data/
- Unit Tests: Each rule has corresponding test class in
tests/Rules/
- Code Standards: Follow PSR-4 autoloading and use ECS for code style
- Testing: All rules must have comprehensive tests with both positive and negative cases
- Documentation: Update README.md and add inline documentation for new rules
- Performance: Ensure rules execute efficiently within PHPStan's analysis pipeline
Cause: Incorrect namespace or class name in phpstan.neon
.
Solution: Verify the fully qualified class names and check for typos.
Cause: Configuration file not included or rules not registered.
Solution: Ensure vendor/simtel/phpstan-rules/rules.neon
is included in your PHPStan configuration.
Cause: Rules may be analyzing too many files or performing expensive operations.
Solution: Use excludePaths
to limit analysis scope or optimize rule logic.
This project is licensed under the MIT License - see the LICENSE file for details.
Contributions are welcome! Please feel free to submit a Pull Request.
If you encounter any issues or have questions, please open an issue on GitHub.