Add them to your phpstan.neon configuration file under the section services.
For detailed documentation of each rule, see the individual rule documentation files in the rules/ directory.
Enforces strict dependency rules for modular hexagonal (Ports and Adapters) architecture with capabilities/modules. This rule is specifically designed for modular monoliths where each capability/module follows a layered architecture pattern.
See Modular Architecture Rule documentation for detailed information.
Detects circular dependencies between modules in a modular architecture. This rule tracks module-to-module dependencies and reports when circular dependencies are detected.
See Circular Module Dependency Rule documentation for detailed information.
Forbids public and/or protected getters and setters on classes matching specified patterns. Useful for enforcing immutability or the "Tell, Don't Ask" principle.
See Forbidden Accessors Rule documentation for detailed information.
Forbids configured control structures (if, for, foreach, while, switch) inside class methods. A global forbiddenStatements list applies to all such methods; optional patterns (regex on Fqcn::methodName) may supply forbiddenStatements per match, which replace the effective list for that method (last matching override wins).
See Forbidden Business Logic Rule documentation for detailed information.
Enforces dependency constraints between namespaces by checking use statements and optionally fully qualified class names (FQCNs). This rule prevents classes in one namespace from depending on classes in another, helping enforce architectural boundaries like layer separation.
See Forbidden Dependencies Rule documentation for detailed information.
Forbids === and !== when both sides are definitely DateTimeInterface, because strict equality is object identity, not same instant. Optional patterns (regex on Fqcn::methodName) limit the rule to matching class methods; an empty patterns list applies globally (unlike Forbidden Else Statements Rule, where empty patterns disables the rule).
See Forbidden Date Time Comparison Rule documentation for detailed information.
Forbids specific static method calls matching regex patterns. Supports namespace-level, class-level, and method-level granularity. The rule resolves self, static, and parent keywords to actual class names.
See Forbidden Static Methods Rule documentation for detailed information.
Ensures that classes matching specified patterns have properties with expected names, types, and visibility scopes. Can optionally enforce that matching classes must have certain properties.
See Property Must Match Rule documentation for detailed information.
Forbids plain else in class methods whose Full\Class\Name::methodName matches any configured regex, using the same Fqcn::methodName convention as other method-scoped rules. Empty patterns disables the rule.
See Forbidden Else Statements Rule documentation for detailed information.
Here is a full example for a modular monolith with clean architecture rules.
services:
# Architecture Rules
# Enforce final classes for controllers
-
class: Phauthentic\PHPStanRules\Architecture\ClassMustBeFinalRule
arguments:
patterns:
- '/^App\\Capability\\.*\\Presentation\\Http\\Controller/'
- '/^App\\Capability\\.*\\Application\\UseCases/'
- '/^App\\Capability\\.*\\Application\\Jobs/'
- '/^App\\Capability\\.*\\Application\\IntegrationEventHandler/'
- '/^App\\Capability\\.*\\Application\\DomainEventHandler/'
- '/^App\\Capability\\.*\\Application\\.*Facade$/'
tags:
- phpstan.rules.rule
# Enforce readonly classes for DTOs and value objects
-
class: Phauthentic\PHPStanRules\Architecture\ClassMustBeReadonlyRule
arguments:
patterns:
- '/^App\\Capability\\.*\\Application\\Transfers/'
- '/^App\\Capability\\.*\\Application\\UseCases\\.*Input$/'
- '/^App\\Capability\\.*\\Application\\UseCases\\.*Result$/'
- '/^App\\Capability\\.*\\Application\\Query\\.*Input$/'
- '/^App\\Capability\\.*\\Application\\Query\\.*Result$/'
- '/^App\\Capability\\.*\\Domain\\Model\\.*\\ValueObject/'
- '/^App\\Capability\\.*\\Application\\.*Facade$/'
tags:
- phpstan.rules.rule
# Dependency constraints - enforce layer boundaries
# Note: Use ForbiddenDependenciesRule (DependencyConstraintsRule is deprecated)
-
class: Phauthentic\PHPStanRules\Architecture\ForbiddenDependenciesRule
arguments:
forbiddenDependencies:
# Domain layer cannot depend on Application, Infrastructure, or Presentation
'/^App\\Capability\\.*\\Domain/':
- '/^App\\Capability\\.*\\Application/'
- '/^App\\Capability\\.*\\Infrastructure/'
- '/^App\\Capability\\.*\\Presentation/'
# Application layer cannot depend on Infrastructure or Presentation
'/^App\\Capability\\.*\\Application/':
- '/^App\\Capability\\.*\\Infrastructure/'
- '/^App\\Capability\\.*\\Presentation/'
# Infrastructure layer cannot depend on Presentation
'/^App\\Capability\\.*\\Infrastructure/':
- '/^App\\Capability\\.*\\Presentation/'
tags:
- phpstan.rules.rule
# Class naming patterns for different layers
-
class: Phauthentic\PHPStanRules\Architecture\ClassnameMustMatchPatternRule
arguments:
namespaceClassPatterns:
# Facades must end with "Facade"
-
namespace: '/^App\\Capability\\.*\\Application$/'
classPatterns:
- '/Facade$/'
- '/FacadeInterface$/'
- '/Exception$/'
- '/Config/'
# Controllers must end with "Controller"
-
namespace: '/^App\\Capability\\.*\\Presentation\\.*\\Controller/'
classPatterns:
- '/Controller$/'
# Repositories must end with "Repository" or "RepositoryInterface"
-
namespace: '/^App\\Capability\\.*\\Domain\\Repository/'
classPatterns:
- '/RepositoryInterface$/'
-
namespace: '/^App\\Capability\\.*\\Infrastructure\\Persistence\\.*\\Repository/'
classPatterns:
- '/Repository$/'
# Aggregate IDs must end with "Id"
-
namespace: '/^App\\Capability\\.*\\Domain\\Model\\.*$/'
classPatterns:
- '/Id$/'
# Transfer objects must end with "Request" or "Result"
-
namespace: '/^App\\Capability\\.*\\Application\\Transfers/'
classPatterns:
- '/Request$/'
- '/Result$/'
# Use case inputs and results
-
namespace: '/^App\\Capability\\.*\\Application\\UseCases/'
classPatterns:
- '/Input$/'
- '/Result$/'
- '/^[A-Z][a-zA-Z0-9]*$/' # Use case classes
# Query inputs and results
-
namespace: '/^App\\Capability\\.*\\Application\\Query/'
classPatterns:
- '/Input$/'
- '/Result$/'
- '/^[A-Z][a-zA-Z0-9]*$/' # Query classes
tags:
- phpstan.rules.rule
# Property rules for entities
-
class: Phauthentic\PHPStanRules\Architecture\PropertyMustMatchRule
arguments:
propertyPatterns:
-
classPattern: '/^App\\Capability\\.*\\Domain\\Model\\.*Entity$/'
properties:
-
name: 'id'
type: 'int'
visibilityScope: 'private'
required: true
-
name: 'createdAt'
type: 'DateTimeImmutable'
visibilityScope: 'private'
required: true
tags:
- phpstan.rules.rule
# Method signature rules for repositories
-
class: Phauthentic\PHPStanRules\Architecture\MethodSignatureMustMatchRule
arguments:
signaturePatterns:
# Repository persist method
-
pattern: '/Repository::persist$/'
minParameters: 1
maxParameters: 1
signature:
-
pattern: '/^[a-zA-Z][a-zA-Z0-9]*$/'
# Repository get method
-
pattern: '/Repository::get$/'
minParameters: 1
maxParameters: 1
tags:
- phpstan.rules.rule
# Method return type rules
-
class: Phauthentic\PHPStanRules\Architecture\MethodMustReturnTypeRule
arguments:
returnTypePatterns:
# Repository get method must return object or null
-
pattern: '/Repository::get$/'
type: 'object'
nullable: true
void: false
objectTypePattern: null
# Repository persist method must return void
-
pattern: '/Repository::persist$/'
type: 'void'
nullable: false
void: true
objectTypePattern: null
# Facade methods must return Result objects
-
pattern: '/Facade::[a-zA-Z]+$/'
anyOf:
- 'regex:/^App\\Capability\\.*\\Application\\.*\\[a-zA-Z]+Result$/'
- void
tags:
- phpstan.rules.rule
# Forbidden namespaces
-
class: Phauthentic\PHPStanRules\Architecture\ForbiddenNamespacesRule
arguments:
forbiddenNamespaces: [
## Matches everything that is NOT in PublicAPI or InternalAPI, modify this only if you want to allow
## new code in other types of presentations!
'/^App\\Capability\\[^\\]+\\Presentation\\(?!Http$|PublicAPI$|InternalAPI$)[^\\]+$/'
]
tags:
- phpstan.rules.rule
# Forbid specific static method calls
-
class: Phauthentic\PHPStanRules\Architecture\ForbiddenStaticMethodsRule
arguments:
forbiddenStaticMethods:
- '/^App\\Legacy\\.*::.*/'
- '/^DateTime::createFromFormat$/'
tags:
- phpstan.rules.rule
# Forbid selected control structures (global + optional per-regex overrides)
-
class: Phauthentic\PHPStanRules\Architecture\ForbiddenBusinessLogicRule
arguments:
forbiddenStatements:
- if
- for
- foreach
- while
- switch
patterns:
-
pattern: '/^App\\Capability\\.*\\Domain\\.*::/'
forbiddenStatements:
- if
- switch
tags:
- phpstan.rules.rule
# Forbid accessors on domain entities
-
class: Phauthentic\PHPStanRules\Architecture\ForbiddenAccessorsRule
arguments:
classPatterns:
- '/^App\\Capability\\.*\\Domain\\Model\\.*Entity$/'
forbidGetters: true
forbidSetters: true
visibility:
- public
tags:
- phpstan.rules.rule
# Clean Code Rules
# Control structure nesting
-
class: Phauthentic\PHPStanRules\CleanCode\ControlStructureNestingRule
arguments:
maxNestingLevel: 3
tags:
- phpstan.rules.rule
# Forbid else in selected class methods (regex on Fqcn::methodName)
-
class: Phauthentic\PHPStanRules\CleanCode\ForbiddenElseStatementsRule
arguments:
patterns:
- '/^App\\Capability\\.*\\Presentation\\Http\\.*Controller::(handle|__invoke)$/'
tags:
- phpstan.rules.rule