Skip to content

Releases: Phauthentic/phpstan-rules

1.9.0 New rules, increased test coverage and bug fixes

09 Feb 23:16
35d68c7

Choose a tag to compare

🎉 New Features

✨ New Rule: Property Must Match Rule

Enforce Property Conventions on Classes

  • Class: Phauthentic\PHPStanRules\Architecture\PropertyMustMatchRule
  • Purpose: Validates that classes matching specified patterns have properties with expected names, types, and visibility scopes
  • Key Features:
    • Required Properties: Enforce that matching classes must have certain properties
    • Type Validation: Check property types including support for union types (int|string) and intersection types (Foo&Bar)
    • Visibility Enforcement: Ensure properties use the correct visibility (public, protected, private)
    • Nullable Support: Optionally accept both a type and its nullable variant (e.g., int and ?int)
    • Flexible Matching: Uses regex patterns to target specific classes
  • Configuration: Supports propertyPatterns parameter with classPattern and properties sub-configuration
  • Error Messages:
    • Class {class} must have property ${name}. (when required property is missing)
    • Property {class}::${name} should be of type {expected}, {actual} given. (type mismatch)
    • Property {class}::${name} must be {visibility}. (visibility mismatch)

Configuration Example:

services:
    -
        class: Phauthentic\PHPStanRules\Architecture\PropertyMustMatchRule
        arguments:
            propertyPatterns:
                -
                    classPattern: '/^App\\Entity\\.*$/'
                    properties:
                        -
                            name: 'id'
                            type: 'int'
                            visibilityScope: 'private'
                            required: true
                        -
                            name: 'createdAt'
                            type: 'DateTimeImmutable'
                            visibilityScope: 'private'
                            required: true
                            nullable: true
        tags:
            - phpstan.rules.rule

✨ New Rule: Forbidden Accessors Rule

Enforce Encapsulation and the "Tell, Don't Ask" Principle

  • Class: Phauthentic\PHPStanRules\Architecture\ForbiddenAccessorsRule
  • Purpose: Forbids public and/or protected getters (getXxx()) and setters (setXxx()) on classes matching specified patterns
  • Key Features:
    • Configurable Accessor Types: Independently control whether getters, setters, or both are forbidden
    • Visibility Control: Choose which visibility levels to check (public, protected)
    • Pattern Matching: Uses regex patterns against fully qualified class names
    • Anonymous Class Safe: Properly skips anonymous classes
  • Configuration: Supports classPatterns, forbidGetters, forbidSetters, and visibility parameters
  • Error Messages:
    • Class {class} must not have a {visibility} getter method {method}().
    • Class {class} must not have a {visibility} setter method {method}().

Configuration Example:

services:
    -
        class: Phauthentic\PHPStanRules\Architecture\ForbiddenAccessorsRule
        arguments:
            classPatterns:
                - '/^App\\Domain\\.*Entity$/'
                - '/^App\\Domain\\.*ValueObject$/'
            forbidGetters: true
            forbidSetters: true
            visibility:
                - public
        tags:
            - phpstan.rules.rule

Use Cases:

  • Enforce immutability on domain entities by forbidding setters
  • Apply the "Tell, Don't Ask" principle by forbidding both getters and setters
  • Restrict only public accessors while allowing protected ones for inheritance

✨ New Rule: Forbidden Static Methods Rule

Prevent Static Method Calls

  • Class: Phauthentic\PHPStanRules\Architecture\ForbiddenStaticMethodsRule
  • Purpose: Forbids specific static method calls matching regex patterns to encourage dependency injection and testability
  • Key Features:
    • Multi-Level Granularity: Supports namespace-level, class-level, and method-level patterns
    • Keyword Resolution: Resolves self, static, and parent keywords to actual class names before matching
    • Dynamic Call Safe: Skips dynamic class names ($class::method()) and dynamic method names (Class::$method())
  • Configuration: Supports forbiddenStaticMethods parameter with an array of regex patterns matching FQCN::methodName
  • Error Messages:
    • Static method call "{call}" is forbidden.

Configuration Example:

services:
    -
        class: Phauthentic\PHPStanRules\Architecture\ForbiddenStaticMethodsRule
        arguments:
            forbiddenStaticMethods:
                - '/^App\\Legacy\\.*::.*/'        # Namespace-level: all legacy static calls
                - '/^App\\Utils\\StaticHelper::.*/' # Class-level: all methods on StaticHelper
                - '/^DateTime::createFromFormat$/'  # Method-level: specific method only
        tags:
            - phpstan.rules.rule

✨ New: ClassNameResolver Trait

Reusable Utilities for FQCN Resolution

  • Trait: Phauthentic\PHPStanRules\Architecture\ClassNameResolver
  • Purpose: Extracts common fully qualified class name resolution and type conversion utilities into a reusable trait
  • Key Methods:
    • resolveFullClassName() — Builds the FQCN from a Class_ or Interface_ node and scope; returns null for anonymous classes
    • getTypeAsString() — Converts type nodes (Identifier, Name, NullableType, UnionType, IntersectionType) to their string representation
    • matchesAnyPattern() — Checks if a string matches any of the given regex patterns
    • normalizeClassName() — Removes the leading backslash from a class name

✨ New: Interactive Rule Config Builder

  • File: rule-builder.html
  • Purpose: An interactive HTML tool for building PHPStan rule configurations visually, making it easier to create correct phpstan.neon configuration without memorizing all parameters

🔧 Code Quality Improvements

🏗️ Refactored Rules to Use ClassNameResolver Trait

Multiple existing rules were refactored to use the new ClassNameResolver trait, reducing code duplication and improving consistency:

  • AttributeRule — Replaced inline FQCN resolution with resolveFullClassName()
  • CatchExceptionOfTypeNotAllowedRule — Added class name normalization for robust comparison (leading backslash handling)
  • ClassMustBeFinalRule — Simplified to use resolveFullClassName() and matchesAnyPattern()
  • ClassMustBeReadonlyRule — Simplified to use resolveFullClassName() and matchesAnyPattern()
  • ClassMustHaveSpecificationDocblockRule — Replaced private matchesPatterns() with trait's matchesAnyPattern()
  • MethodMustReturnTypeRule — Replaced private getTypeAsString() with trait version; now uses FQCN for method matching
  • MethodSignatureMustMatchRule — Replaced private getTypeAsString() with trait version; now uses FQCN for method matching

🔒 Improved Anonymous Class Handling

All class-level rules now properly skip anonymous classes (classes without names) via the resolveFullClassName() method returning null, preventing false positives and potential errors.

✅ Constructor Parameter Validation

Both PropertyMustMatchRule and ForbiddenAccessorsRule validate constructor parameters at instantiation time, throwing InvalidArgumentException for invalid configurations (empty patterns, invalid visibility values).

🔧 Regex Error Handling

PropertyMustMatchRule and ForbiddenAccessorsRule now properly handle preg_match errors, throwing InvalidArgumentException with descriptive messages when an invalid regex pattern is provided.

📦 Dependency Updates

  • Updated phpunit/phpunit from ^12.0 to ^12.5.8

📚 Documentation Improvements

📚 New Documentation Files

  • Forbidden Accessors Rule: Complete documentation with examples for forbidding getters, setters, or both at configurable visibility levels
  • Forbidden Dependencies Rule: Dedicated documentation for the renamed rule with FQCN checking, allowed dependencies, and a Mermaid flowchart explaining the allow/forbid logic
  • Forbidden Static Methods Rule: Full documentation covering namespace-level, class-level, and method-level pattern granularity, including self/static/parent handling
  • Property Must Match Rule: Comprehensive documentation with examples for required properties, optional validation, and nullable types

📚 Updated Documentation

  • README.md: Added Forbidden Accessors Rule, Forbidden Dependencies Rule, Forbidden Static Methods Rule, and Property Must Match Rule to the Architecture Rules list; marked Dependency Constraints Rule as deprecated
  • docs/Rules.md: Added overview sections and full configuration examples for all new rules

✅ New Test Coverage

New Test Files

  • PropertyMustMatchRuleTest: Core functionality tests for property name, type, and required validation
  • PropertyMustMatchRuleNullableTest: Tests for nullable type matching
  • PropertyMustMatchRuleIntersectionTypeTest: Tests for intersection type support
  • PropertyMustMatchRuleInvalidVisibilityTest: Tests for invalid visibility validation
  • PropertyMustMatchRuleInvalidRegexTest: Tests for invalid regex pattern handling
  • PropertyMustMatchRuleExceptionsTest: Tests for constructor validation
  • ForbiddenAccessorsRuleTest: Core functionality tests
  • ForbiddenAccessorsRuleGettersOnlyTest: Tests for forbidding only getters
  • **Forb...
Read more

Version 1.8.0

27 Jan 13:59
c65fd95

Choose a tag to compare

🎉 New Features

✨ New Rule: Attribute Rule

New Rule for PHP 8+ Attribute Validation

  • Class: Phauthentic\PHPStanRules\Architecture\AttributeRule
  • Purpose: Validates PHP 8+ attributes on classes, methods, and properties using regex patterns
  • Key Features:
    • Allowed Attributes: Restrict which attributes can be used on matching targets
    • Forbidden Attributes: Prevent specific attributes from being used
    • Required Attributes: Enforce that certain attributes must be present
    • Flexible Targeting: Match classes, methods, and properties using regex patterns
    • Combined Rules: All three rule types can be applied simultaneously to the same target
  • Configuration: Supports three optional sections:
    • allowed - Define which attributes are permitted (whitelist)
    • forbidden - Define which attributes are prohibited (blacklist)
    • required - Define which attributes must be present

Configuration Example:

services:
    -
        class: Phauthentic\PHPStanRules\Architecture\AttributeRule
        arguments:
            config:
                allowed:
                    # Controllers can only have Route and Cache attributes on methods
                    -
                        classPattern: '/^App\\Controller\\.*/'
                        methodPattern: '/.*Action$/'
                        attributes:
                            - '/^Symfony\\Component\\Routing\\Annotation\\Route$/'
                            - '/^Symfony\\Component\\HttpKernel\\Attribute\\Cache$/'
                forbidden:
                    # Domain layer cannot have framework attributes
                    -
                        classPattern: '/^App\\Domain\\.*/'
                        methodPattern: '/.*/'
                        attributes:
                            - '/^Symfony\\.*/'
                            - '/^Doctrine\\.*/'
                required:
                    # All action methods must have a Route attribute
                    -
                        classPattern: '/^App\\Controller\\.*/'
                        methodPattern: '/.*Action$/'
                        attributes:
                            - '/^Symfony\\Component\\Routing\\Annotation\\Route$/'
        tags:
            - phpstan.rules.rule

Use Cases:

  • Enforce that controller actions only use approved routing attributes
  • Prevent framework-specific attributes in your domain layer (clean architecture)
  • Ensure entity properties only use Doctrine ORM mapping attributes
  • Require specific attributes on classes, methods, or properties
  • Combine all three rule types for comprehensive attribute validation

Error Messages:

  • Forbidden: Attribute {attribute} is forbidden on {type} {name}.
  • Not in allowed list: Attribute {attribute} is not in the allowed list for {type} {name}. Allowed patterns: {patterns}
  • Missing required: Missing required attribute matching pattern {pattern} on {type} {name}.

📚 Updated README

  • Added Attribute Rule to the Architecture Rules list
  • Sorted Architecture Rules list alphabetically for better discoverability

🚀 Migration Guide

For Existing Users

No Action Required! All existing configurations continue to work without any changes. The new Attribute Rule is opt-in and requires explicit configuration.

For New Attribute Rule

To use the new Attribute Rule, add the configuration to your phpstan.neon:

services:
    -
        class: Phauthentic\PHPStanRules\Architecture\AttributeRule
        arguments:
            config:
                allowed:
                    -
                        classPattern: '/^App\\Controller\\.*/'
                        attributes:
                            - '/^Symfony\\Component\\Routing\\Annotation\\Route$/'
                forbidden:
                    -
                        classPattern: '/^App\\Domain\\.*/'
                        attributes:
                            - '/^Symfony\\.*/'
                required:
                    -
                        classPattern: '/^App\\Entity\\.*/'
                        attributes:
                            - '/^Doctrine\\ORM\\Mapping\\Entity$/'
        tags:
            - phpstan.rules.rule

Full Changelog: 1.7.0...1.8.0

1.7.0

15 Jan 18:30
9af22fc

Choose a tag to compare

Release Notes - Version 1.7.0

🎉 New Features

✨ Renamed DependencyConstraintsRule to ForbiddenDependenciesRule

Breaking Change (with full Backward Compatibility!)

  • New Class: Phauthentic\PHPStanRules\Architecture\ForbiddenDependenciesRule
  • Deprecated Class: Phauthentic\PHPStanRules\Architecture\DependencyConstraintsRule
  • Purpose: The new name better reflects the rule's purpose - forbidding specific dependencies between namespaces
  • Migration: The old DependencyConstraintsRule class is kept for backward compatibility but will be removed in a future major version. Please update your configuration to use ForbiddenDependenciesRule instead.

✨ New allowedDependencies Feature for ForbiddenDependenciesRule

Enhancement: Whitelist Override for Forbidden Dependencies

  • Class: Phauthentic\PHPStanRules\Architecture\ForbiddenDependenciesRule
  • Purpose: Allows creating a "forbid everything except X" pattern without complex regex
  • Key Features:
    • New allowedDependencies parameter that overrides forbidden dependencies
    • Dependencies matching both a forbidden pattern and an allowed pattern will be allowed
    • Enables clean domain layer isolation while permitting specific exceptions
  • Configuration: New optional parameter:
    • allowedDependencies (array, default: []) - Whitelist patterns that override forbidden dependencies
  • Use Case Example: Forbid all namespaced dependencies in the domain layer, except for App\Shared, App\Capability, and Psr\*:
services:
    -
        class: Phauthentic\PHPStanRules\Architecture\ForbiddenDependenciesRule
        arguments:
            forbiddenDependencies: [
                '/^App\\Capability\\.*\\Domain$/': [
                    '/.*\\\\.*/'  # Match anything with a backslash (namespaced)
                ]
            ]
            checkFqcn: true
            allowedDependencies: [
                '/^App\\Capability\\.*\\Domain$/': [
                    '/^App\\Shared\\/',
                    '/^App\\Capability\\/',
                    '/^Psr\\/'
                ]
            ]
        tags:
            - phpstan.rules.rule

✨ Required Methods Feature for MethodSignatureMustMatchRule

Enhancement: Enforce Method Implementation in Matching Classes

  • Class: Phauthentic\PHPStanRules\Architecture\MethodSignatureMustMatchRule
  • Purpose: Ensures that classes matching a pattern actually implement a required method with the specified signature
  • Key Features:
    • New required parameter (boolean, default: false)
    • When true, enforces that matching classes must implement the specified method
    • Reports clear error messages with the expected signature when a required method is missing
  • Use Case Example: Ensure all controllers implement an execute method:
services:
    -
        class: Phauthentic\PHPStanRules\Architecture\MethodSignatureMustMatchRule
        arguments:
            signaturePatterns:
                -
                    pattern: '/^.*Controller::execute$/'
                    minParameters: 1
                    maxParameters: 1
                    signature:
                        -
                            type: 'Request'
                            pattern: '/^request$/'
                    visibilityScope: 'public'
                    required: true
        tags:
            - phpstan.rules.rule

🔧 Code Quality Improvements

🏗️ PHPStan Level 8 Compliance

  • Enhancement: All rule classes now pass PHPStan level 8 analysis
  • Improvements:
    • Updated error handling to use IdentifierRuleError instead of generic RuleError
    • Enhanced method signatures with explicit type hints for better clarity and type safety
    • Added parameter type annotations in processNode methods for improved documentation
    • Removed unnecessary instance checks in processNode methods to streamline logic
    • Improved error handling and reporting consistency across all rules

🔧 CI Pipeline Enhancements

  • New Jobs: Added dedicated PHPStan and PHPCS jobs to CI configuration
  • Configuration:
    • Both jobs run on Ubuntu 24.04 with PHP 8.4
    • Ensures static analysis and coding standards are enforced on every push and pull request
  • Benefits:
    • Catches type errors and coding standard violations early
    • Maintains consistent code quality across contributions

📚 Documentation Improvements

📚 New Extending Rules Documentation

  • New File: docs/ExtendingRules.md
  • Purpose: Comprehensive guide for creating domain-specific, self-documenting rules by extending base rules
  • Contents:
    • Benefits of extending rules (self-documenting code, reusability, IDE support, testability)
    • Multiple examples including:
      • Forbidding DateTime in module namespaces
      • Enforcing final classes in domain layer
      • Preventing legacy namespace usage
    • How to customize error messages and identifiers
    • Best practices for organizing custom rules

📚 Updated README

  • New Section: "Domain Specific Rules / Extending Rules" with link to new documentation
  • Enhancement: Clearer explanation of the extensibility features

📚 Enhanced Dependency Constraints Rule Documentation

  • Deprecation Notice: Clear warning about the renamed class
  • New Section: Detailed documentation for the allowedDependencies parameter
  • Diagram: Added Mermaid flowchart explaining the allow/forbid logic
  • Examples: Comprehensive configuration examples for the whitelist feature

📚 Enhanced Method Signature Must Match Rule Documentation

  • New Section: Documentation for the required parameter
  • Example: Complete configuration example for enforcing required methods

🚀 Migration Guide

For Existing Users

No immediate action required! All existing configurations continue to work without changes due to backward compatibility.

Recommended Updates

  1. Rename DependencyConstraintsRule to ForbiddenDependenciesRule:

    Before:

    class: Phauthentic\PHPStanRules\Architecture\DependencyConstraintsRule

    After:

    class: Phauthentic\PHPStanRules\Architecture\ForbiddenDependenciesRule
  2. Consider using allowedDependencies for cleaner "forbid everything except X" patterns instead of complex negative regex.

  3. Consider using the required parameter for MethodSignatureMustMatchRule to enforce method implementation in matching classes.

💡 Why This Matters

Clearer Naming

The rename from DependencyConstraintsRule to ForbiddenDependenciesRule makes the rule's purpose immediately clear - it forbids specific dependencies. This follows the principle of self-documenting code.

Flexible Dependency Control

The new allowedDependencies feature provides a powerful yet simple way to implement "whitelist" patterns. Instead of crafting complex negative lookahead regex patterns, you can now simply:

  1. Forbid everything with a broad pattern
  2. Allow specific exceptions with simple patterns

This significantly simplifies configuration for common architectural patterns like clean architecture domain layers.

Enforce Architectural Contracts

The required parameter for MethodSignatureMustMatchRule enables enforcement of architectural contracts. For example, ensuring all controllers implement a specific execute method guarantees consistency across your application without relying on abstract classes or interfaces.

Extensibility

The new documentation on extending rules encourages creating domain-specific, self-documenting rules. A class named DomainClassesMustBeFinalRule is far more readable than a configuration block with regex patterns.


This release significantly improves the usability and flexibility of the PHPStan rules while maintaining 100% backward compatibility. We recommend updating to the new class names and exploring the new features to improve your architectural enforcement.

Full Changelog: 1.6.0...1.7.0

Enhanced Max Line Length Rule

04 Dec 19:04
cbebe41

Choose a tag to compare

Release Notes - Version 1.6.0

🎉 New Features

✨ Enhanced Max Line Length Rule

Enhancement: Flexible Line Type Ignoring

  • Class: Phauthentic\PHPStanRules\CleanCode\MaxLineLengthRule

  • Purpose: Extended to support ignoring multiple types of lines beyond just use statements, providing more granular control over line length checking

  • Key Features:

    • New Array-Based API: Introduced ignoreLineTypes parameter for flexible configuration
    • Multiple Line Types: Support for ignoring use statements, namespace declarations, and docblocks
    • Backward Compatible: Existing ignoreUseStatements parameter continues to work unchanged
    • Selective Control: Choose which line types to ignore independently
  • Supported Line Types:

    • useStatements - Ignore lines containing use statements (e.g., use Some\Very\Long\Namespace\Path\ClassName;)
    • namespaceDeclaration - Ignore lines containing namespace declarations (e.g., namespace App\Some\Very\Long\Namespace\Path;)
    • docBlocks - Ignore lines that are part of docblock comments (e.g., /** This is a very long docblock comment that exceeds the line length limit */)
  • Configuration: Supports new optional parameter:

    • ignoreLineTypes (array, default: []) - Array of line types to ignore with boolean values
    • ignoreUseStatements (boolean, default: false) - Maintained for backward compatibility, takes precedence when set
  • Backward Compatibility:

    • The existing ignoreUseStatements parameter remains fully functional
    • When both ignoreUseStatements and ignoreLineTypes['useStatements'] are set, ignoreUseStatements takes precedence
    • All existing configurations continue to work without modification

📚 Documentation Improvements

📚 Enhanced Max Line Length Rule Documentation

  • Comprehensive Examples: Added detailed configuration examples for:

    • New array-based API (recommended approach)
    • Legacy parameter usage (backward compatible)
    • Selective line type ignoring
    • Combined configurations
  • Parameter Documentation: Complete documentation of all parameters including:

    • maxLineLength - Maximum allowed line length
    • excludePatterns - File exclusion patterns
    • ignoreUseStatements - Legacy parameter for backward compatibility
    • ignoreLineTypes - New array-based configuration option
  • Use Cases Section: Examples showing:

    • Ignoring only use statements
    • Ignoring namespace declarations and docblocks
    • Ignoring all supported line types
    • Combining with file exclusions

🚀 Migration Guide

For Existing Users

No Action Required! All existing configurations continue to work without any changes. The new ignoreLineTypes parameter is optional and disabled by default, so your current setup will behave exactly as before.

For New Configurations

Recommended: Use the new array-based API for better flexibility:

ignoreLineTypes:
    useStatements: true
    namespaceDeclaration: true
    docBlocks: true

Legacy: The ignoreUseStatements parameter still works and is fully supported:

ignoreUseStatements: true

💡 Why This Matters

The previous version only supported ignoring use statements. Many codebases have long namespace declarations or detailed docblocks that exceed line length limits but are acceptable for readability. This release provides the flexibility to ignore these line types while still enforcing line length limits for actual code logic.

Before (1.5.1): Only use statements could be ignored
After (1.6.0): You can now ignore:

  • Use statements
  • Namespace declarations
  • Docblock comments
  • Any combination of the above

This significantly improves the rule's usability in real-world scenarios where certain types of long lines are acceptable or even preferred for code clarity.


This release represents a major enhancement to the Max Line Length Rule while maintaining 100% backward compatibility with existing configurations. We recommend gradually adopting the new array-based API for better flexibility and future-proofing your configuration.

Full Changelog: 1.5.1...1.6.0

Fixed Max Line Length Rule - Use Statement Ignoring

04 Dec 19:03
2e57a65

Choose a tag to compare

Release Notes - Version 1.5.1

🐛 Bug Fixes

🔧 Fixed Max Line Length Rule - Use Statement Ignoring

Bug Fix: Use Statement Ignoring Not Working Correctly

  • Class: Phauthentic\PHPStanRules\CleanCode\MaxLineLengthRule

  • Issue: When ignoreUseStatements was set to true, the rule was not properly ignoring long use statement lines. The check only examined the node type during initial processing, but didn't account for cases where the same line could be processed multiple times or where use statements appeared on lines that exceeded the maximum length.

  • Solution:

    • Implemented a caching mechanism to track which lines contain use statements per file
    • Added proper line-level checking to ensure use statements are consistently ignored regardless of processing order
    • Enhanced the rule to check both the node type and the cached line information
  • Impact:

    • Use statements that exceed the maximum line length are now correctly ignored when ignoreUseStatements: true is configured
    • Other long lines in the same file continue to be detected as expected
    • No breaking changes - existing configurations continue to work as intended
  • Testing:

    • Added comprehensive test cases to verify use statements are properly ignored
    • Added test cases to ensure non-use statement lines are still detected when use statements are ignored
    • Ensures the fix doesn't break the default behavior of detecting long use statements

💡 Why This Matters

Previously, developers who configured the rule to ignore use statements might have still received false positives for long use statement lines. This fix ensures that when you configure the rule to ignore use statements, those lines are consistently and reliably ignored, allowing you to focus on enforcing line length limits for actual code logic rather than import statements.

Before (1.5.0): Long use statements could still trigger errors even when ignoreUseStatements: true
After (1.5.1): Long use statements are properly ignored when configured, while other long lines are still detected


This is a bug fix release that improves the reliability of the Max Line Length Rule's use statement ignoring feature. All existing configurations continue to work without any changes required.

Full Changelog: 1.5.0...1.5.1

1.5.0

03 Dec 20:32
e99c8c4

Choose a tag to compare

Release Notes - Version 1.5.0

🎉 New Features

✨ Enhanced Dependency Constraints Rule

Enhancement: FQCN (Fully Qualified Class Name) Checking

  • Class: Phauthentic\PHPStanRules\Architecture\DependencyConstraintsRule

  • Purpose: Extended to check not only use statements but also fully qualified class names throughout your codebase

  • Key Features:

    • Backward Compatible: Existing configurations continue to work unchanged (FQCN checking is opt-in)
    • Comprehensive Coverage: Detects forbidden dependencies in 11 different contexts
    • Selective Checking: Configure which reference types to check for optimal performance
    • Flexible Configuration: Enable FQCN checking with a simple boolean flag
  • Supported Reference Types:

    • new - Class instantiations (e.g., new \DateTime())
    • param - Parameter type hints (e.g., function foo(\DateTime $date))
    • return - Return type hints (e.g., function foo(): \DateTime)
    • property - Property type hints (e.g., private \DateTime $date)
    • static_call - Static method calls (e.g., \DateTime::createFromFormat())
    • static_property - Static property access (e.g., \DateTime::ATOM)
    • class_const - Class constant (e.g., \DateTime::class)
    • instanceof - instanceof checks (e.g., $x instanceof \DateTime)
    • catch - catch blocks (e.g., catch (\Exception $e))
    • extends - class inheritance (e.g., class Foo extends \DateTime)
    • implements - interface implementation (e.g., class Foo implements \DateTimeInterface)
  • Configuration: Supports new optional parameters:

    • checkFqcn (boolean, default: false) - Enable FQCN checking
    • fqcnReferenceTypes (array, default: all types) - Select specific reference types to check

📚 Documentation Improvements

📚 Enhanced Dependency Constraints Rule Documentation

  • Comprehensive Examples: Added detailed configuration examples for basic usage, FQCN checking, and selective reference types
  • Use Cases Section: Added real-world examples including:
    • Preventing DateTime usage in domain layers
    • Selective checking for performance optimization
  • Reference Types Documentation: Complete list and explanation of all 11 supported reference types
  • Backward Compatibility Notes: Clear explanation of how existing configurations are unaffected

📚 README Improvements

  • New Section: "What if I need to ignore a Rule in a certain Place?"
    • Explains how to use PHPStan inline annotations
    • Emphasizes keeping rule exceptions documented close to the code
    • Encourages adding comments explaining why a rule is broken

🚀 Migration Guide

For Existing Users

No Action Required! All existing configurations continue to work without any changes. The new FQCN checking feature is disabled by default (checkFqcn: false), so your current setup will behave exactly as before.

💡 Why This Matters

The previous version only checked use statements, which meant developers could bypass dependency constraints by using fully qualified class names. This release closes that loophole while maintaining backward compatibility.

Before (1.4.0): Only use DateTime; would be caught
After (1.5.0): All of these are now caught when checkFqcn: true:

  • use DateTime;
  • new \DateTime()
  • function process(\DateTime $date)
  • function get(): \DateTime
  • private \DateTime $createdAt
  • And 6 more reference types!

This significantly strengthens your architecture enforcement capabilities and helps maintain clean boundaries between layers and modules.


This release represents a major enhancement to the Dependency Constraints Rule while maintaining 100% backward compatibility with existing configurations. We recommend gradually enabling FQCN checking in your projects to ensure complete dependency constraint enforcement.

Full Changelog: 1.4.0...1.5.0

1.4.0

29 Oct 23:49
bcff346

Choose a tag to compare

🎉 New Features

✨ Modular Architecture Rules

New Rule: Modular Architecture Rule

  • Class: Phauthentic\PHPStanRules\Architecture\ModularArchitectureRule
  • Purpose: Enforces strict dependency rules for modular hexagonal (Ports and Adapters) architecture with capabilities/modules
  • Key Features:
    • Enforces intra-module layer dependencies (Domain, Application, Infrastructure, Presentation)
    • Enforces cross-module dependencies using configurable regex patterns
    • Supports custom layer dependency rules
    • Configurable base namespace for capabilities/modules
  • Configuration: Supports baseNamespace, layerDependencies, and allowedCrossModulePatterns parameters
  • Example: Perfect for modular monoliths where each capability/module follows a layered architecture pattern

New Rule: Circular Module Dependency Rule

  • Class: Phauthentic\PHPStanRules\Architecture\CircularModuleDependencyRule
  • Purpose: Detects circular dependencies between modules in a modular architecture
  • Key Features:
    • Tracks module-to-module dependencies
    • Reports circular dependency chains (e.g., Module A → Module B → Module C → Module A)
    • Configurable base namespace for capabilities/modules
  • Configuration: Requires baseNamespace parameter

✨ Specification Docblock Rule

New Rule: Class Must Have Specification Docblock Rule

  • Class: Phauthentic\PHPStanRules\Architecture\ClassMustHaveSpecificationDocblockRule
  • Purpose: Ensures that classes, interfaces, and/or methods matching specified patterns have a properly formatted docblock with a "Specification:" section
  • Key Features:
    • Validates classes and interfaces using regex patterns
    • Validates methods using FQCN::methodName format with regex patterns
    • Configurable specification header text (default: "Specification:")
    • Optional requirement for blank line after header
    • Optional requirement for list items to end with periods
    • Supports annotations after specification section
  • Configuration: Supports classPatterns, methodPatterns, specificationHeader, requireBlankLineAfterHeader, and requireListItemsEndWithPeriod parameters

✨ Enhanced Clean Code Rules

Too Many Arguments Rule - Pattern Support

  • Enhancement: Added optional patterns parameter to apply rule only to classes matching specific regex patterns
  • Backward Compatible: Existing configurations without patterns continue to work (applies to all classes)
  • Example: Can now configure to only check specific classes like '/.*Service$/' or '/App\\Service\\/'

Max Line Length Rule - Use Statement Ignoring

  • Enhancement: Added ignoreUseStatements parameter to optionally ignore use statement lines
  • Configuration: Boolean flag (default: false) to exclude use statements from line length checking

📚 Documentation Improvements

📚 New Documentation Files

  • Modular Architecture Rule: Complete documentation with examples for modular monolith architectures
  • Circular Module Dependency Rule: Full documentation with configuration examples
  • Class Must Have Specification Docblock Rule: Comprehensive documentation with multiple configuration examples for classes, interfaces, and methods
  • Too Many Arguments Rule: Updated documentation with pattern support examples
  • Max Line Length Rule: Updated documentation with ignoreUseStatements parameter

📚 Documentation Structure Improvements

  • Refactored Documentation: Moved all individual rule documentation from docs/Rules.md to individual files in docs/rules/ directory
  • Improved Navigation: Each rule now has its own dedicated documentation file for better discoverability
  • Enhanced Examples: Added comprehensive configuration examples for all new rules
  • Real-world Use Cases: Added practical examples for modular architecture setup

🚀 Migration Guide

For Existing Users

All existing configurations continue to work without changes. The new rules are opt-in and require explicit configuration.

For New Modular Architecture Features

To use the new modular architecture rules:

services:
    -
        class: Phauthentic\PHPStanRules\Architecture\ModularArchitectureRule
        arguments:
            baseNamespace: 'App\\Capability'
            layerDependencies:
                Domain: []
                Application: [Domain]
                Infrastructure: [Domain, Application]
                Presentation: [Application]
            allowedCrossModulePatterns:
                - '/Facade$/'
                - '/FacadeInterface$/'
                - '/Input$/'
                - '/Result$/'
        tags:
            - phpstan.rules.rule
    
    -
        class: Phauthentic\PHPStanRules\Architecture\CircularModuleDependencyRule
        arguments:
            baseNamespace: 'App\\Capability'
        tags:
            - phpstan.rules.rule

For Specification Docblock Validation

To enforce specification docblocks:

services:
    -
        class: Phauthentic\PHPStanRules\Architecture\ClassMustHaveSpecificationDocblockRule
        arguments:
            classPatterns:
                - '/.*Facade$/'
                - '/.*Command$/'
            methodPatterns:
                - '/.*Repository::find.*/'
            specificationHeader: 'Specification:'
            requireBlankLineAfterHeader: true
            requireListItemsEndWithPeriod: false
        tags:
            - phpstan.rules.rule

For Enhanced Clean Code Rules

To use pattern matching with Too Many Arguments Rule:

services:
    -
        class: Phauthentic\PHPStanRules\CleanCode\TooManyArgumentsRule
        arguments:
            maxArguments: 3
            patterns: ['/.*Service$/', '/App\\Controller\\/']
        tags:
            - phpstan.rules.rule

To ignore use statements in Max Line Length Rule:

services:
    -
        class: Phauthentic\PHPStanRules\CleanCode\MaxLineLengthRule
        arguments:
            maxLineLength: 80
            ignoreUseStatements: true
        tags:
            - phpstan.rules.rule

This release significantly expands the capabilities of phpstan-rules, especially for teams working with modular monolith architectures and clean code practices, while maintaining full backward compatibility with existing configurations.

1.2.1

14 Aug 09:56
63f69df

Choose a tag to compare

Release Notes

🐛 Bug Fixes

Final Class Rule

  • Fixed: Abstract classes are now properly ignored by default to prevent false positives
  • Added: Configurable ignoreAbstractClasses parameter (default: true) for users who want to enforce final declaration on abstract classes

Configuration

-
    class: Phauthentic\PHPStanRules\Architecture\ClassMustBeFinalRule
    arguments:
        patterns: ['/^App\\Service\\/']
        ignoreAbstractClasses: true  # Default behavior
    tags:
        - phpstan.rules.rule

Backward Compatible: All existing configurations continue to work without changes.

1.2.0: Improving the MethodMustReturnType to support unions (#7)

29 Jul 13:30
23e5d35

Choose a tag to compare

Release Notes

🎉 New Features

✨ Enhanced Method Must Return Type Rule

  • New Feature: Added support for "void" as a type in addition to the legacy void: true approach
  • New Feature: Added oneOf functionality for union types - allows specifying an array of types where one must match
  • New Feature: Added allOf functionality for union types - allows specifying an array of types where all must be present
  • New Feature: Added anyOf as an alias for oneOf for better readability
  • New Feature: Added regex pattern support in oneOf, allOf, and anyOf arrays using regex: prefix
  • Enhancement: Made configuration fields optional with sensible defaults (nullable, void, objectTypePattern)
  • Enhancement: Added configuration normalization to handle missing fields gracefully

🔧 Configuration Improvements

  • Backward Compatibility: All existing configurations continue to work without changes
  • Flexible Configuration: Minimal configurations now work without requiring all fields
  • Regex Support: Can use patterns like 'regex:/^App\\Entity\\/' to match entity classes

🔧 Documentation Improvements

📚 Enhanced Method Must Return Type Rule Documentation

  • New Examples: Added comprehensive examples for oneOf, allOf, and anyOf usage
  • Regex Documentation: Added documentation for regex pattern support with examples
  • Configuration Guide: Updated configuration examples to show new optional fields
  • Usage Examples: Added real-world examples for entity validation and union types

📚 Updated Configuration Examples

  • New Configuration Patterns: Added examples for minimal configurations
  • Regex Examples: Added examples showing how to use regex patterns for class matching
  • Union Type Examples: Added examples for both oneOf and allOf scenarios

✅ New Test Cases

�� Comprehensive Test Coverage

  • AnyOfRuleTest: Tests for the new anyOf functionality
  • RegexRuleTest: Tests for regex pattern matching in anyOf arrays
  • RegexAllOfRuleTest: Tests for regex pattern matching in allOf arrays
  • EntityRegexRuleTest: Tests for realistic entity pattern matching scenarios
  • FacadeRuleTest: Tests for minimal configuration scenarios
  • UnionTypeRuleTest: Tests for union type functionality
  • Enhanced MethodMustReturnTypeRuleTest: Updated existing tests for new functionality

📁 New Test Data Files

  • data/MethodMustReturnType/AnyOfTestClass.php: Test cases for anyOf functionality
  • data/MethodMustReturnType/EntityRegexTestClass.php: Test cases for entity regex patterns
  • data/MethodMustReturnType/FacadeTestClass.php: Test cases for minimal configurations
  • data/MethodMustReturnType/RegexAllOfTestClass.php: Test cases for allOf with regex
  • data/MethodMustReturnType/RegexTestClass.php: Test cases for basic regex functionality
  • data/MethodMustReturnType/UnionTypeTestClass.php: Test cases for union type validation

🏗️ Code Quality Improvements

🔧 Enhanced MethodMustReturnTypeRule

  • New Methods: Added normalizeConfig(), isTypeMatchWithRegex(), getExpectedTypeDescription()
  • Improved Error Handling: Better error messages for union types and regex patterns
  • Code Organization: Better separation of concerns with dedicated methods for different validation types
  • Type Safety: Enhanced type checking and validation logic

🐛 Bug Fixes

  • Configuration Defaults: Fixed issues with missing configuration fields causing errors
  • Regex Pattern Handling: Proper boolean conversion for regex pattern matching
  • Union Type Parsing: Improved union type parsing and validation logic
  • Error Message Consistency: Standardized error message formatting

📊 Statistics

  • 16 files changed with 700+ lines added and 33 lines removed
  • 17 new test files created for comprehensive coverage
  • 100% backward compatibility maintained with existing configurations

🚀 Migration Guide

For Existing Users

No changes required! All existing configurations will continue to work exactly as before.

For New Features

To use the new union type functionality:

-
    class: Phauthentic\PHPStanRules\Architecture\MethodMustReturnTypeRule
    arguments:
        returnTypePatterns:
            -
                pattern: '/^MyClass::getValue$/'
                anyOf: ['int', 'string', 'bool']
            -
                pattern: '/^MyClass::getEntity$/'
                anyOf: ['regex:/^App\\Entity\\/', 'void']
    tags:
        - phpstan.rules.rule

This release significantly enhances the flexibility and power of the Method Must Return Type Rule while maintaining full backward compatibility.

1.1.0

26 Jul 15:19
ba9dd3c

Choose a tag to compare

Release Notes

🎉 New Features

✨ New Rule: Catch Exception of Type Not Allowed Rule

  • Class: Phauthentic\PHPStanRules\Architecture\CatchExceptionOfTypeNotAllowedRule
  • Purpose: Prevents catching overly broad exception types like Exception, Error, or Throwable
  • Configuration: Accepts an array of forbidden exception types
  • Example: Configure to prevent catching Exception, Error, or Throwable for better error handling practices

✨ Enhanced Method Signature Must Match Rule

  • New Feature: Added visibility scope validation
  • New Feature: Improved parameter validation with optional type checking
  • Enhancement: Better error messages and validation logic
  • Configuration: Now supports visibilityScope parameter (public, protected, private)

🔧 Documentation Improvements

📚 Fixed Class Name References

Updated all configuration examples to use correct class names:

  • ReadonlyClassRuleClassMustBeReadonlyRule
  • FinalClassRuleClassMustBeFinalRule
  • NamespaceClassPatternRuleClassnameMustMatchPatternRule

📚 Added Missing Rule Documentation

  • Methods Returning Bool Must Follow Naming Convention Rule: Complete documentation added with configuration examples
  • Catch Exception of Type Not Allowed Rule: Full documentation with examples

📚 Enhanced Documentation Structure

  • Added anchor links to all rule sections for better navigation
  • Improved README.md with clearer examples
  • Updated namespace references from Phauthentic\PhpstanRules to Phauthentic\PHPStanRules

✅ New Test Cases

  • CatchExceptionOfTypeNotAllowedRuleTest: Comprehensive tests for the new exception catching rule
  • Enhanced MethodSignatureMustMatchRuleTest: Additional test cases for visibility scope and parameter validation

📁 New Test Data Files

  • data/CatchExceptionOfTypeNotAllowed/CatchAllowedException.php: Examples of allowed exception catching
  • data/CatchExceptionOfTypeNotAllowed/CatchForbiddenException.php: Examples of forbidden exception catching
  • Enhanced data/MethodSignatureMustMatch/TestClass.php: Additional test methods for validation

🏗️ Code Quality Improvements

🔧 Refactoring

  • MethodSignatureMustMatchRule: Improved code structure with better separation of concerns
  • MethodMustReturnTypeRule: Enhanced documentation and code comments
  • phpstan.neon: Removed hardcoded rule configurations (now serves as a clean template)

🐛 Bug Fixes

  • Fixed namespace casing inconsistencies (PhpstanRulesPHPStanRules)
  • Improved parameter validation logic in MethodSignatureMustMatchRule
  • Enhanced error message formatting and consistency