itantik / middleware
通用 PHP 中间件实现
v0.2.1
2020-05-27 18:23 UTC
Requires
- php: >= 7.2
Requires (Dev)
- nette/tester: ^2.0
- phpstan/extension-installer: ^1.0
- phpstan/phpstan: ^0.12.19
- squizlabs/php_codesniffer: 3.5.5
This package is auto-updated.
Last update: 2024-09-28 04:53:55 UTC
README
通用 PHP 中间件实现。虽然它与任何 PSR 都有相似之处,但并不符合 PSR 规范。主要目标是提供一个通用的中间件处理器,而不仅仅是 HTTP 请求/响应处理器。
安装
composer require itantik/middleware
用法
让我们看一个例子。
请求
请求实现 Itantik\Middleware\IRequest
接口。否则它是一个普通对象,通常是数据传输对象。
class LoggableRequest implements IRequest { /** @var string[] */ private $logs = []; public function addLog(string $message): void { $this->logs[] = $message; } /** * @return string[] */ public function getLogs(): array { return $this->logs; } }
响应
与请求类似,响应也是一个实现 Itantik\Middleware\IResponse
接口的普通对象。
class LoggableResponse implements IResponse { /** @var string[] */ private $logs = []; public function addLog(string $message): void { $this->logs[] = $message; } /** * @return string[] */ public function getLogs(): array { return $this->logs; } }
中间件
中间件实现 Itantik\Middleware\IMiddleware
接口。
class FirstMiddleware implements IMiddleware { public function handle(IRequest $request, ILayer $nextLayer): IResponse { // do something BEFORE next middleware if ($request instanceof LoggableRequest) { $request->addLog('FirstMiddleware begin'); } // MUST invoke next middleware $resp = $nextLayer->handle($request); // do something AFTER next middleware if ($resp instanceof LoggableResponse) { $resp->addLog('FirstMiddleware end'); } // MUST return response return $resp; } } class SecondMiddleware implements IMiddleware { public function handle(IRequest $request, ILayer $nextLayer): IResponse { // here do nothing BEFORE next middleware // MUST invoke next middleware $resp = $nextLayer->handle($request); // do something AFTER next middleware if ($resp instanceof LoggableResponse) { $resp->addLog('SecondMiddleware end'); } // MUST return response return $resp; } }
一个示例中间件,它将每个请求处理器包装在一个数据库事务中。
class TransactionalMiddleware implements IMiddleware { /** @var Connection */ private $connection; public function __construct(Connection $connection) { $this->connection = $connection; } public function handle(IRequest $request, ILayer $nextLayer): IResponse { $connection = $this->connection; // begin database transaction $connection->beginTransaction(); try { // invoke next middleware $resp = $nextLayer->handle($request); // commit database transaction $connection->commit(); } catch (Exception $e) { // rollback database transaction $connection->rollback(); throw $e; } // return response return $resp; } }
核心层
核心层是中间件链中的最后一个部分。它处理请求并返回响应。核心层实现 Itantik\Middleware\ILayer
接口。
class CoreLayer implements ILayer { public function handle(IRequest $request): IResponse { if ($request instanceof LoggableRequest) { $request->addLog('CoreLayer begin'); } // create response $resp = new LoggableResponse(); $resp->addLog('CoreLayer end'); // return response return $resp; } }
中间件管理器
中间件管理器注册所有中间件,通过它们处理给定的请求并返回响应。
// create middleware manager $manager = new \Itantik\Middleware\Manager(); // register middlewares $manager->append(new FirstMiddleware()); $manager->append(new SecondMiddleware()); // create request $request = new LoggableRequest(); // create core layer for this request $coreLayer = new CoreLayer(); // run it $response = $manager->process($request, $coreLayer); // expected result $requestLogs = $request->getLogs(); // [ // 'FirstMiddleware begin', // 'CoreLayer begin', // ] $responseLogs = $response->getLogs(); // [ // 'CoreLayer end', // 'SecondMiddleware end', // 'FirstMiddleware end', // ] // now we can take another request with appropriate core layer that handles it // and run middleware manager again $response = $manager->process($anotherRequest, $anotherLayer); // and again
传输层
传输层是中间件链中的一个部分。它持有中间件实例和下一层实例。在 handle 方法中,它使用请求和下一层调用中间件处理器。
管理器使用默认的传输层,但你可以创建自己的传输层并向其添加额外的功能。例如,如果你使用来自不受信任来源的中间件,你可以执行一些检查。
// transport layer object class DataTransportLayer implements ILayer { /** @var IMiddleware */ private $middleware; /** @var ILayer */ private $nextLayer; public function __construct(IMiddleware $middleware, ILayer $nextLayer) { $this->middleware = $middleware; $this->nextLayer = $nextLayer; } /** * @param IRequest $request * @return IResponse * @throws MiddlewareException */ public function handle(IRequest $request): IResponse { $res = $this->middleware->handle($request, $this->nextLayer); // check a correct response type returned from each middleware handler if (!($res instanceof DataResponse)) { throw new MiddlewareException( sprintf("Middleware handler must return an instance of '%s'.", DataResponse::class) ); } return $res; } } // transport layer factory class DataTransportLayerFactory implements ITransportLayerFactory { public function create(IMiddleware $middleware, ILayer $nextLayer): ILayer { return new DataTransportLayer($middleware, $nextLayer); } } // add transport layer factory to the manager $manager = new \Itantik\Middleware\Manager(new DataTransportLayerFactory());
要求
- PHP 7.2