PHPArkitect Documentation

repository·main·Indexed 21 days ago

https://github.com/phparkitect/arkitect

A tool for defining and verifying architectural rules in PHP codebases. PHPArkitect allows developers to write constraints—such as namespace dependencies, naming conventions, and inheritance rules—as PHP code and run them in CI to prevent architectural decay. It features a fluent API for defining rules, a CLI for executing checks, baseline management for existing violations, and support for custom rules via the Expression interface.

Tokens
11.7K
Snippets
40
Records
48
Agent score
75%

What's inside PHPArkitect

  1. Namespace dependency rules and global namespace evaluation (v1.0.0)

    main

    In version 1.0.0, PHP core classes are now automatically excluded from dependency checks via reflection. You no longer need to manually list internal classes like \Exception or \DateTime in your rules.

    Warning: Because core classes are auto-excluded, the previous shortcut of 'skipping everything in the root namespace' in DependsOnlyOnTheseNamespaces and NotDependsOnTheseNamespaces has been removed. User-defined classes in the global namespace are now evaluated against your rules.

  2. How custom rules work in PHPArkitect

    main

    PHPArkitect allows you to extend its functionality by writing custom rules for project-specific checks. A rule is any class that implements the Arkitect\Expression\Expression interface. Once implemented, custom rules can be used in your configuration exactly like built-in rules, either as a constraint in should() or as a selector in that().

    $rules[] = Rule::allClasses()
        ->that(new MyCustomSelector())
        ->should(new MyCustomRule(10))
        ->because('reason');
  3. How PHPArkitect rules and concepts work

    main

    PHPArkitect uses a fluent API to define architectural constraints. A Rule consists of a selector (that()), a check (should()), and a reason (because()).

    Core Abstractions

    • ClassSet: The set of PHP files to analyze. Created via ClassSet::fromDir(__DIR__.'/src').
    • Rule: A constraint combining a selector, a check, and a reason. The string passed to because() is displayed in violation reports.
    • Expression: A composable condition used within that() or should() to filter or check classes.

    Rule Modifiers

    • except(): Excludes specific classes from a rule's selector (supports wildcards).
    • andThat(): Narrows the selector by adding additional mandatory conditions.
    • runOnlyThis(): A debugging tool to run only a specific rule during a check run.

    Example Configuration

    <?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[] = Rule::allClasses()
            ->that(new ResideInOneOfTheseNamespaces('App\Controller'))
            ->should(new HaveNameMatching('*Controller'))
            ->because('we want uniform naming for controllers');
    
        $config->add($classSet, ...$rules);
    };
  4. Run PHPArkitect using a Phar

    main

    If your project's dependencies conflict with PHPArkitect's dependencies, use the self-contained Phar distribution.

    Note: The --autoload option is required when using the Phar to ensure your project's classes are discoverable.

    # Download the latest Phar
    wget https://github.com/phparkitect/arkitect/releases/latest/download/phparkitect.phar
    chmod +x pharkitect.phar
    
    # Run checks (replace path with your actual autoload file)
    ./phparkitect.phar check --autoload=vendor/autoload.php
    ./phparkitect.phar check --autoload=vendor/autoload.php
  5. Use `--autoload` when running as a Phar (v1.0.0)

    main

    When running PHPArkitect via a Phar file, you must now explicitly provide the path to your autoload file using the --autoload flag.

    # Old way
    php phparkitect.phar check
    
    # New way
    php phparkitect.phar check --autoload vendor/autoload.php
  6. Update `excludePath()` wildcards (v1.0.0)

    main

    In version 1.0.0, the * wildcard in ClassSet::excludePath() was changed so that it no longer crosses directory separators. To restore the previous behavior of matching across multiple directory levels, use the ** wildcard.

    - $set->excludePath('src/*/Test.php');   // used to match src/A/B/C/Test.php
    + $set->excludePath('src/**/Test.php');  // matches at any depth
  7. Migrate to the `generate-baseline` command (v1.3.0)

    main

    In version 1.3.0, generating a baseline is no longer an option of the check command. It is now a dedicated command. The optional filename is now a positional argument (defaulting to phparkitect-baseline.json).

    Note: The check command will now fail if you attempt to use --generate-baseline to help you identify this migration.

    # Old way
    phparkitect check --generate-baseline
    phparkitect check --generate-baseline my-baseline.json
    
    # New way
    phparkitect generate-baseline
    phparkitect generate-baseline my-baseline.json
  8. Install and Quick Start PHPArkitect

    main

    PHPArkitect allows you to write architectural rules as PHP code and verify them in CI.

    1. Install via Composer

    composer require --dev phparkitect/phparkitect

    2. Initialize configuration Scaffold a phparkitect.php file in your current directory:

    vendor/bin/phparkitect init

    3. Run architectural checks Execute the checks against your codebase:

    vendor/bin/phparkitect check
    composer require --dev phparkitect/phparkitect
    vendor/bin/phparkitect init
    vendor/bin/phparkitect check
  9. Handle baseline line number deprecation (v1.3.0)

    main

    In version 1.3.0, baseline matching no longer depends on line numbers. Violations are identified by the class and the specific report, meaning edits above a violation won't reopen it.

    The --ignore-baseline-linenumbers CLI flag and the $config->ignoreBaselineLinenumbers(true) configuration method are deprecated and will be removed in the next major version.

    Note: Existing baselines will continue to work without regeneration, regardless of whether they contain line numbers.

    - phparkitect check --ignore-baseline-linenumbers
    + phparkitect check
    
    - $config->ignoreBaselineLinenumbers(true);
    + $config;
  10. Manage architectural violations with Baselines

    main

    If your codebase has existing violations that you cannot fix immediately, use a baseline to ignore them during checks.

    Generate a baseline

    Creates a phparkitect-baseline.json file containing current violations.

    phparkitect generate-baseline
    # Or with a custom name
    phparkitect generate-baseline my-baseline.json

    Prune a baseline

    Removes entries from the baseline that no longer match any current violations. This is safer than regenerating because it never adds new violations to the baseline; it only cleans up fixed ones.

    phparkitect prune-baseline

    Using a baseline in check

    Subsequent check runs pick up the default baseline automatically. To use a specific file:

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

    To skip the baseline entirely:

    phparkitect check --skip-baseline

    Matching Logic: Violations are identified by class and rule, not by line number. This means refactoring code (moving lines) won't reopen a known violation.

    phparkitect generate-baseline
    phparkitect prune-baseline
    phparkitect check --use-baseline=my-baseline.json
  11. Test custom rules

    main

    To test a custom rule, treat it as a standard unit test:

    1. Parse a small code fixture into a ClassDescription.
    2. Call evaluate() on the rule instance.
    3. Assert on the contents of the collected Violations.

    Ensure you cover:

    • The passing case.
    • The failing case (and verify the error message).
    • Edge cases handled by appliesTo().