PHPat (PHP Architecture Tester)

repository·main·Indexed 22 days ago

https://github.com/carlosas/phpat

A PHPStan extension that allows developers to define and enforce architectural rules using a natural language abstraction. PHPat provides a fluent assertion API to verify class types, properties, inheritance, and dependencies, enabling the enforcement of layered architectures, MVC decoupling, and restricted vendor coupling through the use of Selectors and Rules.

Tokens
6.6K
Snippets
20
Records
42
Agent score
79%

What's inside PHPat

  1. Overview of PHP Architecture Tester

    main
    PHPat is a PHPStan extension designed for architectural testing. It provides a natural language abstraction that allows developers to define custom architectural rules and verify that the codebase complies with them during static analysis.
  2. What is PHP Architecture Tester (phpat)?

    main
    PHP Architecture Tester (phpat) is a PHPStan extension designed for static analysis to verify architectural requirements in PHP projects. It provides a natural language abstraction that allows developers to define custom architectural rules and assess whether the codebase complies with them.
  3. Leverage PHPStan features with PHP Architecture Tester

    main

    Because PHP Architecture Tester is a PHPStan extension, it inherits all of PHPStan's core capabilities. You can use standard PHPStan features to manage your architecture testing workflow, including:

    • Baseline files: Generate a baseline to ignore existing architecture violations and only report new ones introduced in your code.
    • Output formats: Use various error formatters to customize how architecture violations are displayed.
    • Ignoring errors: Configure specific rules or patterns to be ignored in your analysis.
    • Parallel analysis: Speed up your architecture checks by analyzing multiple files simultaneously.
    • Result Cache: Enable caching to significantly reduce the time required for subsequent analysis runs.
  4. How PHPat works and how to use it

    main

    PHPat (PHP Architecture Tester) is a PHPStan extension used to define and enforce architectural rules in PHP codebases.

    Core Workflow

    1. Define Rules: You create test classes containing methods that define architectural constraints using a fluent API.
    2. Register Tests: You register these test classes in your phpstan.neon configuration file using the phpat.test tag.
    3. Run Analysis: When you run PHPStan, PHPat hooks into the analysis process. It discovers your tests, parses the fluent builder calls into Statement objects, and executes corresponding assertion rules against the AST (Abstract Syntax Tree) nodes of your codebase.

    Assertion Categories

    • Relation assertions: Check relationships between classes (e.g., dependOn, extend, implement, include).
    • Declaration assertions: Check properties of classes themselves (e.g., isAbstract, isFinal, isReadonly).
  5. How Selectors work in PHPat

    main

    Selectors are the mechanism used to define the scope of a PHPat rule. They tell the engine which classes should be evaluated against a specific architectural constraint.

    Selectors can be simple (targeting a single class name) or complex (using logical composition to target groups of classes based on inheritance, namespace, or file structure). By using logical operators like AllOf, AnyOf, and Not, you can build highly granular rules that target specific layers or architectural patterns in your application.

  6. How rule identifiers work for ignoring errors

    main
    When a rule is violated, PHPat generates an error message containing a unique identifier. This identifier is currently derived from the name of the rule's method. You can use this identifier to ignore specific rule violations in your configuration.
  7. Run PHPat development commands

    main

    Use these commands for local development and maintaining the PHPat repository:

    # Fix coding standards
    vendor/bin/php-cs-fixer fix --config ./ci/php-cs-fixer.php
    
    # Run PHPStan with PHPat architecture tests (validates src/ + tests/architecture/)
    vendor/bin/phpstan analyse -c ci/phpstan-phpat.neon
    
    # Run Psalm static analysis
    vendor/bin/psalm -c ci/psalm.xml
    
    # Run tests
    vendor/bin/phpunit tests/unit/ tests/integration/
    
    # Run a single test file
    vendor/bin/phpunit tests/unit/rules/SomeTest.php
  8. Restrict vendor coupling

    main

    You can restrict a specific namespace to only allow dependencies within itself, effectively isolating it from the rest of the application or third-party vendors.

    >Classes in namespace App\Domain can only depend on classes in namespace App\Domain
  9. Enforce interface implementation

    main

    You can mandate that classes within a specific namespace must implement a particular interface. This is a common way to ensure that all Entities or Value Objects adhere to a specific contract.

    >Classes in namespace App\Domain\Entity should implement class with name App\Domain\Entity\EntityInterface
  10. Define architecture rules in PHPat

    main

    A rule is a statement composed of Selectors and Assertions that must be true for a test to pass. In a test class, rules must be defined as public methods that either:

    1. Start with the prefix test_.
    2. Are decorated with the #[TestRule] attribute.

    Rules are constructed using the \PHPat\Test\PHPat::rule() method, which provides a fluent builder interface to select classes and assert their properties or dependencies.

    namespace App	ests\Architecture;
    
    use PHPat\Selector\Selector;
    use PHPat\Test\Attributes\TestRule;
    use PHPat\Test\Builder\Rule;
    use PHPat\Test\PHPat;
    
    final class ConfigurationTest
    {
        public function test_domain_independence(): Rule
        {
            return PHPat::rule()
                ->classes(Selector::inNamespace('App\Domain'))
                ->canOnlyDependOn()
                ->classes(Selector::inNamespace('App\Domain'));
        }
    
        #[TestRule]
        public function entities_are_final(): Rule
        {
            return PHPat::rule()
                ->classes(Selector::extends(Entity::class))
                ->shouldBeFinal();
        }
    }
  11. Enforce layered architecture dependencies

    main

    You can use PHPAT to ensure that architectural layers remain decoupled. For example, in an onion or layered architecture, you can write rules to prevent inner layers (like App\Domain) from depending on outer layers (like App\Application or App\Infrastructure).

    >Classes in namespace App\Domain should not depend on classes in namespace App\Application and classes in namespace App\Infrastructure
    
    >Classes in namespace App\Application should not depend on classes in namespace App\Infrastructure