Skip to content
Analyze/Verify class dependencies for PHP.
Branch: master
Clone or download
Fetching latest commit…
Cannot retrieve the latest commit at this time.
Permalink
Type Name Latest commit message Commit time
Failed to load latest commit information.
.circleci
bin
conf
doc
src
tests
.gitignore
README.md
composer.json
dependency_graph_sample.png

README.md

DependencyAnalyzer

Analyze/Verify dependency map for php.

Latest Stable Version Build Status Scrutinizer Code Quality

Description

Dependency analyzer help you to keep cleaning your architecture.

If you start to managing dependencies between classes likely Clean Architecture or Layered Architecture, you will aware inspecting dependency between classes by eye is very difficult in PHP. This library analyze dependencies in your repository, and take some way of using it to you.(Example: Create UML graph, Verify by your rule, Detect cycle path)

Basic Usages

This library have several functions. If you have error when use them, see Trouble Shooting.

Create dependency graph

graph

php vendor/bin/analyze-deps graph --output ./graph.puml ./some/analyze/dir1 ./some/analyze/dir2

Analysis dependency map and create graph. Now, dependency analyzer support only Plant UML format.

Maybe, your graph will have many classes, and is very complex! If you need to simplify your graph, see Advanced Usage.

Verify your dependency rule

In Clean Architecture, there is dependency rules between classes. You can define your dependency rule, and this library will detect rule violation in your repository and notify them to you.

First, you can define your rule by php file, like below:

<?php
// ./your_rule_file.php

return [
    'layer dependency rule' => [                // name of your rule
        'domain_layer' => [                     // component name
            'define' => ['\Acme\Domain'],       // component definition by namespace
            'depender' => ['application_layer'] // rule of component dependency, for depender
        ],
        'application_layer' => [
            'define' => ['\Acme\Application'],
            'depender' => ['controller_layer']
        ],
        'controller_layer' => [
            'define' => ['\App', '!\App\Providers']
        ]
    ],
//    'some more rules' => [
//        'SomeComponent' => ['...'],
//        '...' => []
//    ]
];

'component' is a group of classes. (About class name matching rule, see wiki.) 'depender' is classes/components that depend on component. 'dependee' is classes/components that is depended on component. You can restrict depender/dependee. Then, you can verify your repository like this:

php vendor/bin/analyze-deps verify --rule ./your_rule_file.php ./some/analyze/dir1 ./some/analyze/dir2

If there is rule violation, notify you of them.

layer dependency rule
+------------------------------------+------------------+----+---------------------------+--------------+
| depender                           | component        |    | dependee                  | component    |
+------------------------------------+------------------+----+---------------------------+--------------+
| App\UseCaseRequests\GetUserRequest | controller_layer | -> | Acme\Domain\Entities\User | domain_layer |
+------------------------------------+------------------+----+---------------------------+--------------+

And, you can use phpdoc too. You can restrict depener of class by writing @canOnlyUsedBy.

<?php
namespace Acme\Domain\ValueObjects;

/**
 * @canOnlyUsedBy \Acme\Domain\Entities\User
 * @canOnlyUsedBy \Acme\Application\Responses\GetUserResponse
 */
class UserName
{
    // ...
}

Then, you can verify your repository. (command is same as above) Of course, you can use rule file and phpdoc at same time. In the process of analyse, this library collect @canOnlyUsedBy, and verify your repository. If there is rule violation, notify you of them.

phpdoc in Acme\Domain\ValueObjects\UserName
+------------------------------------------------+-----------+----+-----------------------------------+-----------+
| depender                                       | component |    | dependee                          | component |
+------------------------------------------------+-----------+----+-----------------------------------+-----------+
| Acme\Application\Repositories\UserRepository   | other     | -> | Acme\Domain\ValueObjects\UserName | phpdoc    |
| Acme\Application\Responses\CreateUserResponse  | other     | -> | Acme\Domain\ValueObjects\UserName | phpdoc    |
| Acme\Application\UseCases\CreateUserInteractor | other     | -> | Acme\Domain\ValueObjects\UserName | phpdoc    |
+------------------------------------------------+-----------+----+-----------------------------------+-----------+

More example about rule file, see this repository rule file.

Detect cycle dependency

In Acyclic dependencies principle, dependencies graph should have no cycles. You can detect cycles like this:

php vendor/bin/analyze-deps detect-cycle ./some/analyze/dir
+---------------------------------------------+----+
| class                                       |    |
+---------------------------------------------+----+
| App\Http\Controllers\Api\UserController     | -> |
| Acme\Application\UseCases\GetUserInteractor | -> |
| Acme\Domain\Entities\User                   | -> |
| App\Http\Controllers\UserController         | -> |
| App\UseCaseRequests\GetUserRequest          | -> |
| App\Http\Controllers\Api\UserController     |    |
+---------------------------------------------+----+

What is dependency?

Dependency is knowledge of interface that is had by class. In classes collaboration, every class always have knowledge of interface of other classes. If a interface is changed, classes what have knowledge of that interface is must fixed.

Dependency is created by below php syntaxes.

  • extends/implements
  • use trait
  • new object
  • type hinting (defined by phpdoc too)
  • return type declaration (defined by phpdoc too)
  • fetch public property/constant
  • call public method
  • class class method
  • throw
  • catch
  • instanceof
  • foreach access
  • array dim access
  • call function

This library analyze those syntaxes by using PHPStan, and create dependency graph. If you want to know detail, see example.

Trouble shooting

Error has occurred when analyse repository

Every command have verbose option. So use it, check error detail.

-v: Display description of exceptions. -vv: Display detail of exception with stack trace.

Error has occurred when resolving dependency

PHPStan need autoloader (likely vendor/autoload.php ) of repository. So, current working directory is must repository root.

Rule violation was not detected

Define rule by phpdoc(@canOnlyUsedBy)

There are two possible causes.

The first possibility is that the dependency is not analyzed correctly. Output a graph, and check that the analysis result is what you expected. If it is different, the target code is that can not be statically analyzed, or a bug of this library.

php vendor/bin/analyze-deps graph --output ./graph.puml ./some/analyze/dir1 ./some/analyze/dir2

The second possibility is that this library can not collect phpdoc(@canOnlyUsedBy). Use verify command with -v option. You can check the final rule definition.

php vendor/bin/analyze-deps verify -v ./some/analyze/dir1 ./some/analyze/dir2

If you do not find a rule definition like below, this library have failed to collect phpdoc. Please adjust the position of phpdoc, or check typo.

Defined rules:
array (
  'phpdoc in Your\\Class\\Name\\Have\\Phpdoc' => 
  array (
    'phpdoc' => 
    array (
      'define' => 
      array (
        'include' => 
        array (
          0 => 'Your\\Class\\Name\\Have\\Phpdoc',
        ),
        'exclude' => 
        array (
        ),
      ),
      'depender' => 
      array (
        'include' => 
        array (
          0 => 'Your\\Definition1\\In\\Phpdoc',
          1 => 'Your\\Definition2\\In\\Phpdoc',
        ),
        'exclude' => 
        array (
        ),
      ),
    ),
    'other' => 
    array (
      'define' => 
      array (
        'include' => 
        array (
        ),
        'exclude' => 
        array (
          0 => 'Your\\Definition1\\In\\Phpdoc',
          1 => 'Your\\Definition2\\In\\Phpdoc',
        ),
      ),
    ),
  ),
)

Advanced Usages

Create dependency graph

TBD...

  • rule file
  • namespace
  • group
  • comment

Verify your dependency rule

TBD...

  • namespace rule
  • magic keyword

TODO

  • Display error details
  • README
    • graph
    • wiki
  • Analyze Facade
  • Response object & format
    • use table format
  • comment of Plant UML
  • fix namespace pattern matting(adjust file pattern matting)
    • only !\Hoge\Fuga
  • Graph format(another puml)
  • original rule logic
    • remove dependency to vertex, edge
  • Improve performance by using cache
  • Analyze per class member(property/method/constant)
You can’t perform that action at this time.