Friday, March 13, 2026

Chain of Responsibility Design Pattern in PHP

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

  1. Promotes flexibility by allowing dynamic addition or removal of handlers.
  2. Makes request processing modular and maintainable.
  3. Reduces large conditional logic by delegating responsibility.

Weaknesses

  1. Debugging may be harder when requests travel through the entire chain.
  2. Performance may degrade if the chain grows too long.
  3. Overuse may introduce unnecessary complexity.

Opportunities

  1. Helps build middleware-style request pipelines.
  2. Encourages modular responsibility delegation.
  3. Provides foundation for PSR-15 middleware frameworks.

Threats

  1. Misordered handlers may cause incorrect processing.
  2. Tightly coupled handlers defeat the pattern’s purpose.
  3. Poor exit conditions may result in unhandled requests.

No comments:

Chain of Responsibility Design Pattern in PHP

Chain of Responsibility Design Pattern in PHP 🔗 What Is the Chain of Responsibility Pattern? The Chain of Responsibility is a behavio...