Circular Reference

ID

php.circular_reference

Severity

high

Remediation Complexity

medium

Remediation Risk

medium

Remediation Effort

medium

Resource

Reliability

Language

Php

Tags

inheritance, reliability

Description

Reports inheritance cycles between classes (or interfaces) across the whole project: a chain of extends relationships that loops back on itself, such as A extends B, B extends C, C extends A. The check is project-wide — the classes that form the cycle may be declared in different files and namespaces.

Rationale

A class hierarchy must be a tree (or, for interfaces, a directed acyclic graph): every type has at most one parent and that chain of parents must eventually terminate. When the chain loops back on itself, the type can never be resolved or instantiated. In practice a cycle is a fatal error in PHP and signals one of two mistakes: two classes that were refactored until each references the other, or a copy-paste that names the wrong parent. Surfacing the cycle pinpoints the declaration that closes the loop.

<?php
// file model/a.php
namespace App\Model;

class A extends B {}            // OK - this edge alone does not close a cycle

// file model/b.php
namespace App\Model;

class B extends A {}            // FLAW - closes the inheritance cycle App\Model\A -> App\Model\B -> App\Model\A

// file model/chain.php
namespace App\Linear;

class Base {}
class Middle extends Base {}    // OK - linear chain, terminates at Base
class Leaf extends Middle {}    // OK - linear chain, terminates at Base

Remediation

Break the cycle. Decide which class is genuinely the more general one and keep only that extends direction; extract the shared behaviour the two classes were trying to reach for into a common base class or an interface, or replace the inheritance with composition so neither type needs to extend the other.