Small Interfaces
The Interface Segregation Principle says: no class should be forced to implement methods it does not need. Instead of one fat interface with many methods, make several small ones — each class implements only what is true for it.
PHP interfaces fit this rule naturally: a class declares exactly the interfaces it implements — nothing more — and when some code really needs several abilities, small interfaces combine with extends. Keeping each interface tiny keeps every implements list honest.
The Fat Interface
A Worker interface with work() and eat() looks harmless — until a robot applies for the job. The robot works fine, but it must implement eat() too, with... something. Nonsense answers like this are the signature of a fat interface.
The robot forced to eat
The robot implements eat() only because the interface demands it. The lunch break prints an answer that should never exist — the class was forced to lie.
Output: PHP script
<?php
// One fat interface — every worker MUST also eat.
interface Worker {
public function work(): string;
public function eat(): string;
}
class Human implements Worker {
public function work(): string {
return "human: working";
}
public function eat(): string {
return "human: eating lunch";
}
}
class Robot implements Worker {
public function work(): string {
return "robot: working";
}
// Forced by the interface — robots do not eat.
public function eat(): string {
return "robot: ERROR, cannot eat";
}
}
$team = [new Human(), new Robot()];
foreach ($team as $w) {
echo $w->work(), "\n";
}
foreach ($team as $w) {
echo $w->eat(), "\n";
}
Split the Interface
Split the fat interface into Worker and Eater. The human implements both; the robot implements only Worker. The work shift takes workers, the lunch break takes eaters — the robot is simply never invited to lunch, and no method lies.
Each class implements only its truth
Two small interfaces instead of one fat one. The robot no longer has an eat() method at all — the Eater type hint keeps it out of the lunch break automatically.
Output: PHP script
<?php
// Two small interfaces — each class implements only its truth.
interface Worker {
public function work(): string;
}
interface Eater {
public function eat(): string;
}
class Human implements Worker, Eater {
public function work(): string {
return "human: working";
}
public function eat(): string {
return "human: eating lunch";
}
}
class Robot implements Worker {
public function work(): string {
return "robot: working";
}
}
function workShift(Worker ...$team): void {
foreach ($team as $w) {
echo $w->work(), "\n";
}
}
function lunchBreak(Eater ...$guests): void {
foreach ($guests as $e) {
echo $e->eat(), "\n";
}
}
workShift(new Human(), new Robot());
lunchBreak(new Human());
Small Pieces Compose
Small interfaces are not a limitation — they combine. When some function really needs both abilities, compose them into one interface: WorkingEater extends Worker, Eater.
That is the pattern: define small interfaces, and glue them together with extends only where more is truly needed.
Compose when you need both
WorkingEater is built from the two small interfaces with extends. The human declares that one interface and thereby counts as a Worker and an Eater too — the full-day shift needs both abilities, so only the human qualifies.
Output: PHP script
<?php
interface Worker {
public function work(): string;
}
interface Eater {
public function eat(): string;
}
// Small interfaces compose into bigger ones when needed.
interface WorkingEater extends Worker, Eater {
}
class Human implements WorkingEater {
public function work(): string {
return "human: working";
}
public function eat(): string {
return "human: eating lunch";
}
}
function fullDay(WorkingEater $we): void {
echo $we->work(), "\n";
echo $we->eat(), "\n";
echo $we->work(), "\n";
}
fullDay(new Human());