Abandoned
This package is abandoned in favor of
maglnet/composer-require-checker
,
which is well maintained and is
natively supported by GrumPHP.
Composer require checker is more rich in
features,
it is kept up-to-date, and importantly, uses the same
MIT license., (*1)
, (*2)
Introduction
MediaCT Dependency Guard is a static code analyzer that determines whether your
package is depending on code that is installed as a side-effect of your developer
and / or test environment., (*3)
Installation
composer require --dev mediact/dependency-guard
The tool can then be used in 3 ways:, (*4)
- As a composer command
- As a stand-alone command
- As GrumPHP task
Composer command
composer dependency-guard
Stand-alone
vendor/bin/dependency-guard
GrumPHP task
Invoke GrumPHP using the provided configuration., (*5)
Usage
When running the DependencyGuard, it will look for all files that are accessible
through the autoload configuration of composer.json
., (*6)
It will traverse all files, trying to detect PHP files and then determining the
symbols (class, interface, trait) used by each file., (*7)
When the symbols are gathered, it determines to which package each symbol belongs.
If a package is detected that is not installed because of the require
section,
but because of the require-dev
section in composer.json
, a violation is
registered., (*8)
Also, when it is determined that a package is installed, while no code is using
that package, another violation is registered., (*9)
, (*10)
In the example above, the package mediact/data-container
is installed as dev
package, yet used directly in the code of the current package., (*11)
Additionally, the package league/container
is installed, but none of its code
is directly used., (*12)
To use custom reporting of these violations, JSON is supported as export format:, (*13)
, (*14)
Configuring exceptions
There are circumstances when dependency violations happen intentionally., (*15)
Suggest
For instance, when a package is supplying factories for multiple implementations
of a specific factory, that require different packages for each factory. In that
case, the package would require those implementations as dev-package, and also
list them under the suggest
section of their composer.json
., (*16)
When a package is added to the suggest
section, its violations are ignored by
the dependency guard:, (*17)
{
"require": {
"psr/http-message-implementation": "@stable"
},
"require-dev": {
"guzzlehttp/psr7": "^1.4"
},
"suggest": {
"guzzlehttp/psr7": "To use the Guzzle PSR7 implementation."
}
}
Exclude symbols
To exclude specific symbols, add the following to the
extra.dependency-guard.exclude
section of composer.json
:, (*18)
{
"extra": {
"dependency-guard": {
"exclude": [
"Specific\\Class\\To\\Exclude",
"Specific\\Namespace\\",
"Some\\Class\\Matching\\Foo*"
]
}
}
}
Symbols can be excluded using an exact match, a namespace match or a pattern used
by fnmatch., (*19)
The configuration above will exclude:, (*20)
Specific\Class\To\Exclude
Specific\Namespace\Bunny
Some\Class\Matching\FooBarBaz
Ignore packages
To ignore violation messages for a specific package, add the following to the
extra.dependency-guard.ignore
section of composer.json
:, (*21)
{
"extra": {
"dependency-guard": {
"ignore": [
"acme/tnt",
"symfony/",
"league/fly*"
]
}
}
}
Packages can be ignored using an exact match, a vendor match or a pattern used
by fnmatch., (*22)
The configuration above will ignore violations for the following packages:, (*23)
acme/tnt
symfony/console
league/flysystem
Known limitations
Some scenarios cannot be covered by Dependency Guard, in its current form.
Known limitations are listed below:, (*24)
🦊 Pokémon exception handling combined with integration tests
Pókemon exception handling is also known as:, (*25)
This methodology catches any and all exceptions and either forwards them or ignores them:, (*26)
<?php
try {
doSomething();
} catch (Throwable $exception) {
// Do nothing.
}
When this is used to handle exceptions in an application, the following issue is caused by
running integration tests on that code., (*27)
When the test sets an expectation / assertion, the assertion may fail. When the assertion
fails, it throws a corresponding exception, which is meant to be caught by the test framework., (*28)
Instead it is caught by the exception handling as described above. To counteract this, the
following ends up in production code:, (*29)
<?php
try {
doSomething();
} catch (\PHPUnit\Framework\AssertionFailedError $assertionException) {
// Re-throw the exception, as it is part of the testing framework.
throw $assertionException;
} catch (Throwable $exception) {
// Do nothing.
}
The code above causes DependencyGuard, to detect that
\PHPUnit\Framework\AssertionFailedError
is a symbol that can only be available when
a development installation is used. It may be expected that, since this symbol is only
used within a catch
, it is not "really" a dependency, as it will only be autoloaded
when that specific exception is thrown. DependencyGuard does no such specific inspection
of the symbol at hand. The exception is thus marked as dependency violation., (*30)
There are currently no plans to solve this. That being said, pull requests and open
discussions on this matter are welcomed., (*31)