phpat icon indicating copy to clipboard operation
phpat copied to clipboard

PHP Architecture Tester - Easy architecture testing for PHP :heavy_check_mark:

PHP Architecture Tester

Easy to use architecture testing tool for PHP

Version PHP Version Contributions welcome


⚠ PHPat has been converted into a PHPStan extension in v0.10
The standalone version (v0.9) will be still available and will receive critical bugfixes if needed.


Introduction 📜

PHP Architecture Tester is a static analysis tool to verify architectural requirements.

It provides a natural language abstraction to define your own architectural rules and test them against your software. You can also integrate phpat easily into your toolchain.

There are four groups of supported assertions: Dependency, Inheritance, Composition and Mixin.

ℹī¸ Check out the section WHAT TO TEST to see some examples of typical use cases.

Installation đŸ’Ŋ

Just require phpat with Composer:

composer require --dev phpat/phpat
Manual download

If you have dependency conflicts, you can also download the latest PHAR file from Releases.

You will have to use it executing php phpat.phar phpat.yaml and declare your tests in XML or YAML.

Configuration 🔧

You will need to setup a minimum configuration:

# phpat.yaml
src:
  path: src/
tests:
  path: tests/architecture/
Complete list of options
Name Description Default
src path The root path of your application no default
src include Files you want to be tested excluding the rest all files
src exclude Files you want to be excluded in the tests no files
composer $ALIAS json Path of your composer.json file (multiple) main json
composer $ALIAS lock Path of your composer.lock file (multiple) main lock
tests path The path where your tests are no default
tests baseline Path to a generated baseline file no default
options verbosity Output verbosity level (-1/0/1/2) 0
options php-version PHP version of the src code (x.x.x) PHP_VERSION
options ignore-docblocks Ignore relations on docblocks (T/F) false
options ignore-php-extensions Ignore relations to core and extensions classes (T/F) true
--generate-baseline Option to generate a json baseline file (null/filename) false

Test definition 📓

There are different Selectors to choose which classes will intervene in a rule and a wide range of Assertions.

This could be a test with a couple of rules:

<?php

use PhpAT\Rule\Rule;
use PhpAT\Selector\Selector;
use PhpAT\Test\ArchitectureTest;
use App\Domain\BlackMagicInterface;

class ExampleTest extends ArchitectureTest
{
    public function testDomainDoesNotDependOnOtherLayers(): Rule
    {
        return $this->newRule
            ->classesThat(Selector::haveClassName('App\Domain\*'))
            ->excludingClassesThat(Selector::implementInterface(BlackMagicInterface::class))
            ->canOnlyDependOn()
            ->classesThat(Selector::havePath('Domain/*'))
            ->andClassesThat(Selector::haveClassName('App\Application\Shared\Service\KnownBadApproach'))
            ->build();
    }
    
    public function testAllHandlersExtendAbstractCommandHandler(): Rule
    {
        return $this->newRule
            ->classesThat(Selector::havePath('Application/*/UseCase/*Handler.php'))
            ->excludingClassesThat(Selector::extendClass('App\Application\Shared\UseCase\DifferentHandler'))
            ->andExcludingClassesThat(Selector::includeTrait('App\Legacy\LegacyTrait'))
            ->andExcludingClassesThat(Selector::haveClassName(\App\Application\Shared\UseCase\AbstractCommandHandler::class))
            ->mustExtend()
            ->classesThat(Selector::haveClassName('App\Application\Shared\UseCase\AbstractCommandHandler'))
            ->build();
    }
}
YAML / XML test definition

You can also define tests whether in YAML or XML.

rules:
  testAssertionsImplementAssertionInterface:
    - classes:
        - havePath: Rule/Assertion/*
    - excluding:
        - haveClassName: PhpAT\Rule\Assertion\*\MustNot*
        - havePath: Rule/Assertion/MatchResult.php
    - assert: mustExtend
    - classes:
        - haveClassName: PhpAT\Rule\Assertion\AbstractAssertion
<?xml version="1.0" encoding="UTF-8" ?>
<test xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="https://raw.githubusercontent.com/carlosas/phpat/master/src/Test/Test.xsd">
    <rule name="testAssertionsDoNotDependOnVendors">
        <classes>
            <selector type="havePath">Rule/Assertion/*</selector>
        </classes>
        <assert>canOnlyDependOn</assert>
        <classes>
            <selector type="haveClassName">PhpAT\*</selector>
            <selector type="haveClassName">Psr\*</selector>
        </classes>
    </rule>
</test>

Usage 🚀

Run the bin with your configuration file:

vendor/bin/phpat phpat.yaml

⚠ Launching early stage releases (0.x.x) could break the API according to Semantic Versioning 2.0. We are using minor for breaking changes. This will change with the release of the stable 1.0.0 version.

PHP Architecture Tester is in a early stage, contributions are welcome. Please have a look to the Contribution docs.