Chain of Responsibility Design Pattern in PHP
🔗 What Is the Chain of Responsibility Pattern?
The Chain of Responsibility is a behavioral design pattern that lets you pass a request through a chain of handlers, where each handler decides either to process the request or pass it to the next handler in line.
Think of it like a helpdesk ticket system — your request moves up the support chain until someone has the authority or ability to resolve it.
🤔 Why Would I Use It in PHP?
- When multiple classes could handle a request and you don’t want the sender to know which one will do it.
- When you want to decouple the sender and receiver, making the system easier to maintain.
- When you need a flexible structure for handling requests such as logging, validation, or middleware.
✅ Benefits of Using It in PHP
- Enables clean separation of concerns by letting each handler focus on a specific task.
- Makes code extensible, allowing handlers to be added, removed, or reordered easily.
- Reduces tight coupling between components sending and processing requests.
UML / ORM
🌟 Chain of Responsibility — Participants (for PHP Students)
Handler
- Defines the interface for handling requests.
- Stores a reference to the next handler.
- Forwards requests if it cannot handle them.
ConcreteHandler
- Handles requests it is responsible for.
- Decides whether to process or forward.
- Passes unhandled requests to the successor.
Client
- Sends requests to the first handler.
- Does not know which handler processes the request.
- Relies on the chain to handle requests.
PHP 8.2 Implementation
Handler.php
<?php
interface Handler
{
public function setNext(Handler $handler): Handler;
public function handle(string $request): ?string;
}
AbstractHandler.php
<?php
require_once 'Handler.php';
abstract class AbstractHandler implements Handler
{
protected ?Handler $nextHandler = null;
public function setNext(Handler $handler): Handler
{
$this->nextHandler = $handler;
return $handler;
}
public function handle(string $request): ?string
{
if ($this->nextHandler) {
return $this->nextHandler->handle($request);
}
return null;
}
}
ConcreteHandlerA.php
<?php
require_once 'AbstractHandler.php';
class ConcreteHandlerA extends AbstractHandler
{
public function handle(string $request): ?string
{
if ($request === 'A') {
return "Handler A: I handled the request.";
}
return parent::handle($request);
}
}
ConcreteHandlerB.php
<?php
require_once 'AbstractHandler.php';
class ConcreteHandlerB extends AbstractHandler
{
public function handle(string $request): ?string
{
if ($request === 'B') {
return "Handler B: I handled the request.";
}
return parent::handle($request);
}
}
ConcreteHandlerC.php
<?php
require_once 'AbstractHandler.php';
class ConcreteHandlerC extends AbstractHandler
{
public function handle(string $request): ?string
{
if ($request === 'C') {
return "Handler C: I handled the request.";
}
return parent::handle($request);
}
}
index.php
setNext($b)->setNext($c);
$requests = ['A','B','C','D'];
foreach ($requests as $request) {
echo "Client: Who can handle '$request'?\n";
$result = $a->handle($request);
if ($result) {
echo $result . "\n";
} else {
echo "No handler could handle the request.\n";
}
echo "----------------------------------------\n";
}
Expected Output
Client: Who can handle 'A'? Handler A: I handled the request. ---------------------------------------- Client: Who can handle 'B'? Handler B: I handled the request. ---------------------------------------- Client: Who can handle 'C'? Handler C: I handled the request. ---------------------------------------- Client: Who can handle 'D'? No handler could handle the request.
🧠S.W.O.T. Analysis — Chain of Responsibility in PHP
Strengths
- Promotes flexibility by allowing dynamic addition or removal of handlers.
- Makes request processing modular and maintainable.
- Reduces large conditional logic by delegating responsibility.
Weaknesses
- Debugging may be harder when requests travel through the entire chain.
- Performance may degrade if the chain grows too long.
- Overuse may introduce unnecessary complexity.
Opportunities
- Helps build middleware-style request pipelines.
- Encourages modular responsibility delegation.
- Provides foundation for PSR-15 middleware frameworks.
Threats
- Misordered handlers may cause incorrect processing.
- Tightly coupled handlers defeat the pattern’s purpose.
- Poor exit conditions may result in unhandled requests.






