Cyclic Namespace Dependencies
ID |
php.cyclic_namespace_dependencies |
Severity |
low |
Remediation Complexity |
medium |
Remediation Risk |
low |
Remediation Effort |
medium |
Resource |
Code Smell |
Language |
Php |
Tags |
code_smell, namespaces |
Description
Reports namespaces that participate in a circular dependency. A dependency edge from
namespace A to namespace B exists when a file declaring A imports a symbol from B
through a use statement. When following those edges in the project leads back to the
starting namespace, the namespaces form a cycle and every namespace on the cycle is flagged.
Rationale
Cyclic namespace dependencies tightly couple parts of a codebase that should be independent. A namespace caught in a cycle cannot be understood, tested, reused, or moved on its own because it transitively depends on itself through its neighbours. Cycles also make the build and autoloading order ambiguous and tend to grow over time, hardening into an impossible-to-refactor knot. Breaking the cycle keeps the dependency graph a clean acyclic hierarchy.
<?php
// File AlphaService.php
namespace App\Alpha; // FLAW — App\Alpha -> App\Beta -> App\Alpha
use App\Beta\BetaService;
class AlphaService
{
private BetaService $beta;
}
// File BetaService.php
namespace App\Beta; // FLAW — closes the cycle back to App\Alpha
use App\Alpha\AlphaService;
class BetaService
{
private AlphaService $alpha;
}
Remediation
Break the cycle by introducing a one-directional dependency. Extract the shared abstraction (an interface or a value object) into a third namespace that both sides depend on, or move the type that is referenced in both directions so the edges point one way only. Depending on abstractions rather than concrete classes across namespace boundaries keeps the dependency graph acyclic.