3

我已经从PHP-FIG(HTTP 服务器请求处理程序)中阅读了 PSR-15,并且想知道何时调用一个动作(控制器动作或闭包)。

通过所有中间件进行处理时,应在传递所有中间件后调用该操作。在操作之后,所有中间件再次从内部传递到外部(如Slim 框架的用户指南中所述)。

我在 GitHub 上浏览了 Laravel 的代码,但不知道他们是如何调用动作然后再次遍历所有中间件的。

这个答案告诉我 Slim 将自己添加到中间件堆栈中。我猜它然后以某种方式执行动作。但是,Slim 使用的是双通道。

中间件堆栈和执行如何通过单次传递(如 PSR-15 中所述)并在所有中间件之间调用操作?

4

2 回答 2

1

这是一个示例代码,我可以想象它可以工作。当然,还缺少很多东西,比如设置路由、解决依赖关系、PSR 接口和其他框架附带的东西。

此代码将中间件和操作添加到请求处理程序,请求处理程序可以在需要时执行两者。

<?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();
于 2019-08-24T08:20:14.663 回答
1

我开始实际将控制器添加为中间件。为此,RequestHandler 必须能够接受要添加的新中间件。我的路由器负责分配适当的中间件。这样我也可以为每条路线分配多个动作。

于 2018-06-20T16:24:24.687 回答