mindplay / middleman

PSR-7 中间件分发器。让我们停止尝试使它变得复杂。

4.0.4 2024-08-30 09:07 UTC

README

PHP Version CI Code Coverage

简单易懂的PSR-15/PSR-7中间件分发器。

提供(可选)与兼容PSR-11的依赖注入容器的集成。

要升级到主要版本,请参阅UPGRADING.md

github.com/middlewares提供不断增长的PSR-15中间件组件目录。

用法

构造函数期望一个PSR-15 MiddlewareInterface 实例数组

use mindplay\middleman\Dispatcher;

$dispatcher = new Dispatcher([
    new ErrorHandlerMiddleware(...)
    new RouterMiddleware(...),
    new NotFoundMiddleware(...),
]);

Dispatcher 实现了PSR-15 RequestHandlerInterface。本包仅提供中间件栈 - 要运行PSR-15处理程序,例如在您的 index.php 文件中,您需要一个 PSR-15 主机 或类似设施。

请注意,Dispatcher 中的中间件栈是不可变的 - 如果您需要一个可操作的栈,则 arrayArrayObjectSplStack 等都是不错的选择。

匿名函数作为中间件

您可以通过在中间件栈中使用匿名函数来实现简单的中间件“就地”。

use Psr\Http\Message\ServerRequestInterface;
use mindplay\middleman\Dispatcher;
use Nyholm\Psr7\Factory\Psr17Factory;

$factory = new Psr17Factory();

$dispatcher = new Dispatcher([
    function (ServerRequestInterface $request, callable $next) {
        return $next($request); // delegate control to next middleware
    },
    function (ServerRequestInterface $request) use ($factory) {
        return $factory->createResponse(200)->withBody(...); // abort middleware stack and return the response
    },
    // ...
]);

$response = $dispatcher->handle($request);

通过解析函数进行依赖注入

如果您想与IOC 容器集成,您可以使用 ContainerResolver - “解析器”是一个可调用的函数,它应用于您的中间件栈中的每个元素,其签名如下:

function (string $name) : MiddlewareInterface

以下示例从DI容器动态获取中间件组件

$dispatcher = new Dispatcher(
    [
        RouterMiddleware::class,
        ErrorMiddleware::class,
    ],
    new ContainerResolver($container)
);

如果您希望 Dispatcher 深度集成到您选择的框架中,您可以将此实现为实现了魔法 __invoke() 函数的类(如 ContainerResolver 所做) - 或者“就地”,作为一个具有匹配签名的匿名函数。

如果您想精确了解此组件的工作原理,整个组件只是一个包含几行代码的类Dispatcher.php - 如果您打算基于中间件构建您的下一个项目,您可以(并且应该)理解整个机制。

中间件?

中间件是一种强大而简单的控制设施。

如果您对中间件的概念不熟悉,以下部分将提供一个基本概述。

简而言之,中间件组件是一个函数(或 MiddlewareInterface 实例),它接受一个传入的(PSR-7)RequestInterface 对象,并返回一个 ResponseInterface 对象。

它通过以下三种方式之一来完成此操作:通过 承担委托共享 责任来创建响应对象。

1. 承担责任

中间件组件通过创建和返回一个响应对象来承担责任,而不是将责任委托给堆栈中的下一个中间件

use Zend\Diactoros\Response;

function ($request, $next) {
    return (new Response())->withBody(...); // next middleware won't be run
}

堆栈顶部的中间件有权完全跳过堆栈中更低的中间件。

2. 委派责任

通过调用$next,堆栈顶部的中间件可以选择将创建响应的责任完全委托给堆栈中更低的中间件组件

function ($request, $next) {
    if ($request->getMethod() !== 'POST') {
        return $next($request); // run the next middleware
    } else {
        // ...
    }
}

注意,耗尽中间件堆栈将导致异常 - 假设堆栈中最后一个中间件组件始终会以某种形式产生响应,通常是“404未找到”错误页面。

3. 共享责任

堆栈顶部的中间件可以选择将创建响应的责任委托给堆栈中更低的中间件,然后在返回之前对返回的响应进行额外更改

function ($request, $next) {
    $result = $next($request); // run the next middleware

    return $result->withHeader(...); // then modify it's response
}

堆栈顶部的中间件组件最终拥有最多的控制权,因为它可以在返回之前覆盖响应对象的任何属性。