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.