Chain of Responsibility Design Pattern in PHP

1. Definition

The Chain of Responsibility pattern is a behavioral design pattern that decouples senders from receivers by allowing more than one object to handle a request. This chain consists of several processing objects, each of which knows about its successor. If one object cannot handle the request, it passes it to its successor.

2. Problem Statement

Imagine a scenario where an event or a request should be processed by one of several handler objects, but we don’t know beforehand which handler should process it, or we want to allow dynamic determination of the handler.

3. Solution

The Chain of Responsibility pattern comes to the rescue by creating a chain of potential handlers for the event or request. The request travels through the chain until a handler takes the responsibility to process it.

4. Real-World Use Cases

1. Logging frameworks where different levels of log messages are handled differently.

2. Event handling systems in GUI libraries.

3. Middleware in web frameworks where each piece of middleware modifies the request or response.

5. Implementation Steps

1. Define a Handler interface that specifies a method to set the next handler and a method to process the request.

2. Implement concrete handlers that process requests they are responsible for or pass it to the next handler in the chain.

3. Create the chain by linking handlers together.

6. Implementation in PHP

<?php
// Handler interface
interface Handler {
    public function setNext(Handler $handler): Handler;
    public function handle(string $request): ?string;
}
// Base handler
abstract class AbstractHandler implements Handler {
    private ?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;
    }
}
// Concrete handlers
class FirstHandler extends AbstractHandler {
    public function handle(string $request): ?string {
        if ($request === "first") {
            return "First handler handles request: " . $request;
        }
        return parent::handle($request);
    }
}
class SecondHandler extends AbstractHandler {
    public function handle(string $request): ?string {
        if ($request === "second") {
            return "Second handler handles request: " . $request;
        }
        return parent::handle($request);
    }
}
// Client code
$firstHandler = new FirstHandler();
$secondHandler = new SecondHandler();
$firstHandler->setNext($secondHandler);
echo $firstHandler->handle("first") . "\n";
echo $firstHandler->handle("second") . "\n";
?>

Output:

First handler handles request: first
Second handler handles request: second

Explanation:

In the example, there's an abstract AbstractHandler class implementing the Handler interface, which maintains the chain's structure. Each concrete handler (FirstHandler and SecondHandler) either processes the request if it's responsible for it or forwards it to the next handler.

In the client code, the handlers are linked in a chain, and the request is processed as it passes through the chain until a handler processes it.

7. When to use?

Use the Chain of Responsibility pattern when:

1. More than one object should have the opportunity to process a request.

2. You want to decouple senders from receivers.

3. The set of objects that can process a request should be specified dynamically.


Comments