SkillAgentSearch skills...

Arkitect

Put your architectural rules under test!

Install / Use

/learn @phparkitect/Arkitect
About this skill

Quality Score

0/100

Supported Platforms

Universal

README

📐 PHPArkitect

Latest Stable Version PHPArkitect Packagist codecov

  1. Introduction
  2. Quick Start
  3. Installation
  4. Usage
  5. Available rules
  6. Rule Builders
  7. Integrations

Introduction

PHPArkitect is a tool to enforce architectural constraints in your PHP codebase. It helps you maintain clean architecture by preventing violations of your design rules during development and in CI/CD pipelines.

Why PHPArkitect?

As projects grow, maintaining architectural consistency becomes challenging. PHPArkitect helps you:

  • Prevent architectural drift: Ensure your Domain layer doesn't depend on Infrastructure code
  • Enforce naming conventions: Make sure all Controllers end with "Controller", all Services with "Service", etc.
  • Maintain layered architecture: Keep your application, domain, and infrastructure layers properly separated
  • Catch violations early: Get immediate feedback in your IDE or CI pipeline before code review
  • Document architecture as code: Your architectural rules become executable and self-documenting

Example

You can express architectural constraints in simple, readable PHP code:

Rule::allClasses()
    ->that(new ResideInOneOfTheseNamespaces('App\Controller'))
    ->should(new HaveNameMatching('*Controller'))
    ->because('it\'s a symfony naming convention');

Rule::allClasses()
    ->that(new ResideInOneOfTheseNamespaces('App\Domain'))
    ->should(new NotHaveDependencyOutsideNamespace('App\Domain'))
    ->because('we want to protect our domain from external dependencies');

Since selecting classes by namespace is very common, there's a convenient shortcut:

Rule::namespace('App\Controller')
    ->should(new HaveNameMatching('*Controller'))
    ->because('it\'s a symfony naming convention');

You can also specify multiple namespaces: Rule::namespace('App\Controller', 'App\Service').

Quick Start

Get started with PHPArkitect in 3 simple steps:

1. Install via Composer

composer require --dev phparkitect/phparkitect

2. Create a configuration file

Create a phparkitect.php file in your project root:

<?php
declare(strict_types=1);

use Arkitect\ClassSet;
use Arkitect\CLI\Config;
use Arkitect\Expression\ForClasses\HaveNameMatching;
use Arkitect\Expression\ForClasses\ResideInOneOfTheseNamespaces;
use Arkitect\Rules\Rule;

return static function (Config $config): void {
    $classSet = ClassSet::fromDir(__DIR__.'/src');

    $rules = [];

    $rules[] = Rule::allClasses()
        ->that(new ResideInOneOfTheseNamespaces('App\Controller'))
        ->should(new HaveNameMatching('*Controller'))
        ->because('we want uniform naming for controllers');

    $config->add($classSet, ...$rules);
};

3. Run the check

vendor/bin/phparkitect check

That's it! PHPArkitect will analyze your code and report any architectural violations.

Next steps: Check out the Available rules section to explore all the constraints you can enforce.

Installation

Using Composer

composer require --dev phparkitect/phparkitect

Using a Phar

Sometimes your project can conflict with one or more of PHPArkitect's dependencies. In that case you may find the Phar (a self-contained PHP executable) useful.

The Phar can be downloaded from GitHub:

wget https://github.com/phparkitect/arkitect/releases/latest/download/phparkitect.phar
chmod +x phparkitect.phar
./phparkitect.phar check

When you run phparkitect as phar and you have custom rules in need of autoloading the project classes you'll need to specify the option --autoload=[AUTOLOAD_FILE].

Usage

To use this tool you need to launch a command via Bash:

phparkitect check

With this command phparkitect will search for the default config file called phparkitect.php in the root of your project. You can also specify your configuration file using --config option like this:

phparkitect check --config=/project/yourConfigFile.php

By default, a progress bar will show the status of the ongoing analysis.

Using a baseline file

If there are a lot of violations in your codebase and you can't fix them now, you can use the baseline feature to instruct the tool to ignore past violations.

To create a baseline file, run the check command with the generate-baseline parameter as follows:

phparkitect check --generate-baseline

This will create a phparkitect-baseline.json, if you want a different file name you can do it with:

phparkitect check --generate-baseline=my-baseline.json

It will produce a json file with the current list of violations.

If a baseline file with the default name is present, it will be used automatically.

To use a different baseline file, run the check command with the use-baseline parameter as follows:

phparkitect check --use-baseline=my-baseline.json

To avoid using the default baseline file, you can use the skip-baseline option:

phparkitect check --skip-baseline

Line numbers in baseline

By default, the baseline check also looks at line numbers of known violations. When a line before the offending line changes, the line numbers change and the check fails despite the baseline.

With the optional flag ignore-baseline-linenumbers, you can ignore the line numbers of violations:

phparkitect check --ignore-baseline-linenumbers

Warning: When ignoring line numbers, phparkitect can no longer discover if a rule is violated additional times in the same file.

Output format

Output format can be controlled using the parameter format=[FORMAT]. There are two available output formats

  • text: the default one
  • json: this format allows custom report using github action or another platform as Sonarqube and so on... Note that this will suppress any output apart from the violation reporting.
  • gitlab: this follows Gitlab's code quality format. Note that this will suppress any output apart from the violation reporting.

Configuration

Example of configuration file phparkitect.php

<?php
declare(strict_types=1);

use Arkitect\ClassSet;
use Arkitect\CLI\Config;
use Arkitect\Expression\ForClasses\HaveNameMatching;
use Arkitect\Expression\ForClasses\NotHaveDependencyOutsideNamespace;
use Arkitect\Expression\ForClasses\ResideInOneOfTheseNamespaces;
use Arkitect\Rules\Rule;

return static function (Config $config): void {
    $mvcClassSet = ClassSet::fromDir(__DIR__.'/mvc', __DIR__.'/lib/my-lib/src');

    $rules = [];

    $rules[] = Rule::allClasses()
        ->that(new ResideInOneOfTheseNamespaces('App\Controller'))
        ->should(new HaveNameMatching('*Controller'))
        ->because('we want uniform naming');

    $rules[] = Rule::allClasses()
        ->that(new ResideInOneOfTheseNamespaces('App\Domain'))
        ->should(new NotHaveDependencyOutsideNamespace('App\Domain'))
        ->because('we want to protect our domain');

    $config
        ->add($mvcClassSet, ...$rules);
};

PHPArkitect can detect violations also on DocBlocks custom annotations (like @Assert\NotBlank or @Serializer\Expose). If you want to disable this feature you can add this simple configuration:

$config->skipParsingCustomAnnotations();

Available rules

Hint: If you want to test how a Rule work, you can use the command like phparkitect debug:expression <RuleName> <arguments> to check which class satisfy the rule in your current folder.

For example: phparkitect debug:expression ResideInOneOfTheseNamespaces App


Currently, you can check if a class:

Namespace

Reside in a namespace / Not reside in a namespace

// Enforce that all handlers live in the application layer
$rules[] = Rule::allClasses()
    ->that(new HaveNameMatching('*Handler'))
    ->should(new ResideInOneOfTheseNamespaces('App\Application'))
    ->because('we want to be sure that all CommandHandlers are in a specific namespace');

// Ensure domain events do not leak into other layers
$rules[] = Rule::allClasses()
    ->that(new Extend('App\Domain\Event'))
    ->should(new NotResideInTheseNamespaces('App\Application', 'App\Infrastructure'))
    ->because('we want to be sure that all events not reside in wrong layers');

Reside in a namespace exactly / Not reside in a namespace exactly

These rules check namespace membership without matching child namespaces. Unlike ResideInOneOfTheseNamespaces which matches recursively, these rules only match classes directly in the given namespace.

// Only allow entity classes at the root Entity namespace, not in subdirectories
$rules[] = Rule::allClasses()
    ->that(new HaveNameMatching('*Entity'))
    ->should(new ResideInOneOfTheseNamespacesExactly('App\Domain\Entity'))
    ->because('we want entity classes only in the root Entity namespace, not in subdirectories');

// Prevent classes from sitting directly at the Legacy namespace root
$rules[] = Rule::allClasses()
    ->that(new ResideInOneOfTheseNamespaces('App\Legacy'))
    ->should(new NotResideInOneOfTheseNamespacesExactly('App\Legacy'))
    ->because('we want to avoid classes directly in the Legacy namespace root');

For example, with namespace App\Domain\Entity:

  • App\Domain\Entity\User ✅ matches ResideInOneOfTheseNamespacesExactly
  • `App\Domain\Entity\ValueObject\Email
View on GitHub
GitHub Stars886
CategoryDevelopment
Updated2d ago
Forks53

Languages

PHP

Security Score

100/100

Audited on Apr 1, 2026

No findings