phanalist

E0022: The “Traffic Jam” Rule (Afferent & Efferent Coupling)

Imagine a city intersection.

If an intersection has 20 roads coming in and 20 roads going out, it’s a nightmare. If one road closes, the whole city stops.

This rule measures the traffic flowing in and out of your Namespaces.

How the rule works

We look at an entire namespace (like App\Domain\Billing) and count the connections:

  1. Ca (Incoming): How many external classes use classes from Billing? If this is high, Billing is very important and must be carefully tested, because changing it breaks other things.
  2. Ce (Outgoing): How many external classes do the classes in Billing use? If this is high, Billing is very fragile, because if any of those external things change, Billing breaks.

If either score gets too high (default > 20), your namespace is tangled up in a traffic jam.


❌ The “Traffic Jam” Example

This namespace is highly coupled to the outside world (High Ce).

namespace App\Services\Reporting;

// High Ce! We are depending on DB, Mail, PDF, Excel, S3, and Logger 
// namespaces just to generate a report.
use App\Infrastructure\Database\Connection;
use App\Infrastructure\Mail\SmtpMailer;
use App\Vendors\PdfGenerator;
use App\Vendors\ExcelWriter;
use App\Infrastructure\Storage\S3Bucket;
use App\Infrastructure\Logging\Syslog;

class ReportGenerator {
    // ...
}

✅ The “Clean Intersection” Example

Use interfaces to invert the dependencies so your namespace doesn’t rely on the outside world directly.

namespace App\Services\Reporting;

// Ce = 0! We don't depend on infrastructure. 
// We define our own interfaces, and the outside world must adapt to us.
interface MailerInterface {}
interface StorageInterface {}

class ReportGenerator {
    public function __construct(MailerInterface $mailer, StorageInterface $storage) {}
}

Configuration

rules:
  E0022:
    max_ca: 20
    max_ce: 20

The Junior’s Rule of Thumb:

If Phanalist flags your namespace for Ca or Ce, it means your folders are too tangled together. Use interfaces to break the dependencies between different parts of your app!