Interfaces
debt(d5/e3/b5/t3)
Closest to 'specialist tool catches it' (d5). The detection_hints list phpstan and psalm — both static analysis tools that can flag type hints to concrete classes where an interface would be more appropriate, or interfaces that violate segregation. These are specialist tools, not default linters or compiler errors.
Closest to 'simple parameterised fix' (e3). The quick_fix is to define an interface and update injection points to use it rather than the concrete class. This is a small, focused refactor — typically touching the interface definition, the injection site, and possibly a DI container binding — but stays within one component and follows a clear replace-pattern approach.
Closest to 'persistent productivity tax' (b5). Interfaces apply across all contexts (web, cli, queue-worker) and are tagged with solid/principles, meaning architectural decisions about interface granularity (ISP violations, over-interfacing, concrete-class coupling) shape how testable and swappable the entire codebase is. Poor interface hygiene affects many work streams — testing, mocking, dependency injection — but doesn't quite define the system's shape the way an ORM choice would.
Closest to 'minor surprise' (t3). The misconception is that small single-method interfaces are too trivial to be worth defining, when in fact they are among the most powerful patterns. This is a single notable edge case — undervaluing small interfaces — rather than a deep behavioural contradiction. Common mistakes (over-interfacing, ISP violations, naming conventions) are real but well-documented and learnable quickly.
Also Known As
TL;DR
Explanation
PHP interfaces define public method signatures without implementation. A class that implements an interface guarantees it provides those methods, enabling code to depend on the interface contract rather than a concrete implementation — a key principle of Dependency Inversion. Interfaces support multiple implementation (unlike single-class inheritance), can extend other interfaces, and since PHP 8.0 can declare constants. Type-hinting against interfaces rather than concrete classes is the basis of testable, loosely coupled PHP architecture.
Common Misconception
Why It Matters
Common Mistakes
- Creating interfaces for every class regardless of whether multiple implementations exist or are planned.
- Putting too many methods in one interface — violates Interface Segregation, forces implementors to stub unused methods.
- Naming interfaces with I prefix (IMailer) — PHP convention is to use the role name (Mailer, MailerInterface).
- Duplicating the concrete class method signatures exactly — interfaces should model client needs, not implementation details.
Code Examples
// Concrete type dependency — cannot swap implementations:
class OrderService {
public function __construct(private MySQLOrderRepository $repo) {}
}
// Interface-based — swappable:
interface OrderRepositoryInterface {
public function find(int $id): Order;
public function save(Order $o): void;
}
class OrderService {
public function __construct(private OrderRepositoryInterface $repo) {}
}
// Interfaces define contracts — no implementation
interface Mailer {
public function send(Message $message): void;
public function sendBulk(array $messages): int;
}
interface Loggable {
public function toLog(): array;
}
// A class can implement multiple interfaces
class SmtpMailer implements Mailer {
public function send(Message $message): void {
// SMTP implementation
}
public function sendBulk(array $messages): int {
foreach ($messages as $m) { $this->send($m); }
return count($messages);
}
}
// Type hint the interface — never the concrete class
class NotificationService {
public function __construct(private Mailer $mailer) {} // swappable
}