Coupling
debt(d5/e7/b7/t5)
Closest to 'specialist tool catches' (d5). The term's detection_hints list phpstan, phpmd, and deptrac as tools that can identify coupling issues through metrics like afferent/efferent coupling and dependency analysis. These are specialist static analysis tools, not default linters, so coupling problems require deliberate tooling setup to detect automatically.
Closest to 'cross-cutting refactor' (e7). While the quick_fix suggests injecting dependencies and depending on abstractions, actually decoupling tightly coupled code typically requires changes across many files — introducing interfaces, refactoring constructors, updating instantiation sites, and potentially restructuring module boundaries. It's rarely a single-line fix; it's architectural work that spans the codebase.
Closest to 'strong gravitational pull' (b7). Coupling decisions shape how every future change propagates through the system. The term applies to all PHP contexts (web, cli, queue-worker) and is tagged as architecture/principles. Once tight coupling is established, it acts as a persistent tax — every modification risks rippling through coupled modules, and the coupling pattern tends to spread as developers follow existing conventions.
Closest to 'notable trap' (t5). The misconception explicitly states that developers wrongly believe 'any dependency between modules is bad coupling.' This is a documented gotcha that most developers eventually learn — the real goal is loose coupling via abstractions, not zero coupling. The common_mistakes (hidden singleton coupling, Law of Demeter violations) represent patterns that look fine but create invisible coupling.
Also Known As
TL;DR
Explanation
Coupling measures how much changing one module forces changes in others. Types range from loose (data coupling via parameters) to tight (content coupling where one module directly modifies another's internals). High coupling is a primary driver of brittle, hard-to-test code. It is reduced by programming to interfaces, using dependency injection, applying the Law of Demeter, and introducing well-defined boundaries between modules. Coupling and cohesion are twin concerns — high cohesion within a module naturally reduces coupling to other modules.
Common Misconception
Why It Matters
Common Mistakes
- Instantiating dependencies with new inside a class instead of injecting them.
- Accessing global state or singletons directly — hidden coupling that is invisible in the signature.
- Returning concrete types instead of interfaces — callers become coupled to the implementation.
- Reaching into chained objects: $order->getCustomer()->getAddress()->getCity() — violates Law of Demeter and couples deeply.
Code Examples
// High coupling: PaymentService directly instantiates and calls Stripe SDK
class PaymentService {
public function charge(int $cents): void {
$stripe = new \Stripe\Charge();
$stripe->create(['amount' => $cents, 'currency' => 'usd']);
}
}
// Low coupling: depends on an interface, not a concrete class
interface PaymentGateway {
public function charge(int $cents, string $currency): ChargeResult;
}
class PaymentService {
public function __construct(private PaymentGateway $gateway) {}
public function charge(int $cents): ChargeResult {
return $this->gateway->charge($cents, 'usd');
}
}
class StripeGateway implements PaymentGateway { ... }