Here is an example code as I could imagine that could work. Of course, there are a lot of things missing like setting routes, resolving dependencies, PSR interfaces and other things that come with frameworks.
This codes adds middleware and action to the request handler and the request handler can execute both when needed.
<?php
interface RequestInterface {}
class Request implements RequestInterface {}
interface ResponseInterface {}
class Response implements ResponseInterface {}
class Response404 implements ResponseInterface {}
class FirstMiddleware {
public function process(RequestInterface $request, RequestHandler $handler): ResponseInterface {
echo ' First-Before ';
$response = $handler->handle($request);
echo ' First-After ';
return $response;
}
}
class SecondMiddleware {
public function process(Request $request, RequestHandler $handler): Response {
echo ' Second-Before ';
$response = $handler->handle($request);
echo ' Second-After ';
return $response;
}
}
class RequestHandler {
private $middleware;
private $callable;
private $params;
public function __construct(array $middleware = [], callable $callable, array $params = []) {
$this->middleware = $middleware;
$this->callable = $callable;
$this->params = $params;
}
public function handle(RequestInterface $request): ResponseInterface {
$middleware = current($this->middleware);
next($this->middleware);
if (!$middleware) {
$response = ($this->callable)(...$this->params);
return $response;
}
return $middleware->process($request, $this);
}
}
class App {
private $middleware = [];
private $callable;
public function setMiddleware(array $middleware) {
$this->middleware = $middleware;
}
public function setCallable(callable $callable) {
$this->callable = $callable;
}
public function run() {
$handler = new RequestHandler($this->middleware, $this->callable, ['one', 'two']);
$handler->handle(new Request());
}
}
class Controller {
public function action($a, $b) {
echo ' Controller Action ';
echo $a;
echo $b;
return new Response();
}
}
$middleware = [
new FirstMiddleware(),
new SecondMiddleware(),
];
// Using closure ...
$callable = function ($a, $b) {
echo ' Closure Action ';
echo $a;
echo $b;
return new Response();
};
// Or an object method
$controller = new Controller();
$callable = array($controller, 'action');
/** Run */
$app = new App();
$app->setMiddleware($middleware);
$app->setCallable($callable);
$app->run();