处理器 (Handler)
处理器(Handler)
是整个框架的内核,是 Psr\Http\Server\RequestHandlerInterface
的一个实现。它承载了一次请求处理的主要逻辑,与传统框架不同的是,FLuff 的内核是作为组件提供的。在开始一切之前,你首先要做的是选用一个 Handler 作为框架的核心。
处理器可以直接作为内核使用,也可以配合调度器对 Request
进行动态处理。Handler
的选择对于整体架构至关重要,它会影响到后续的应用开发方式,并且选择之后很难替换。所以,了解每一种处理器的运行机制是必要的。
处理器 (Handler)
处理器可以看做是对单个接口的处理逻辑,它不接受路由
的调度,只是对业务代码的简单的包装。实际上,我们在快速入门章节中已经使用到了一个处理器 Handler
. 接下来将详细介绍三种处理器
静态调用 (Handler)
这种处理器的规则最简单,首先定义一个 callable
对象,然后 Handler 会向这个对象传入一个 Server Request
对象,然后直接调用它。callable
对象必须返回一个 Psr\Http\Message\ResponseInterface
的实例。
use ConstanzeStandard\Fluff\Application;
use ConstanzeStandard\Fluff\Middleware\EndOutputBuffer;
use ConstanzeStandard\Fluff\RequestHandler\Handler;
use Nyholm\Psr7\ServerRequest;
use Nyholm\Psr7\Response;
use Psr\Http\Message\ServerRequestInterface;
$handler = new Handler(function(ServerRequestInterface $request, array $args) {
return new Response(200, [], 'Hello '. $args['name']);
}, ['name' => 'World']);
$app = new Application($handler);
$app->addMiddleware(new EndOutputBuffer());
$request = new ServerRequest('GET', '/');
$app->handle($request);
Handler
的第二个参数接受一个数组,你可以利用它向 callable
对象的内部传递额外的信息。
延迟加载 (Delay Handler)
如果你希望将 callable
对象的初始化延迟到 Sub Middleware 之后,可以使用 DelayHandler
.
use ConstanzeStandard\Fluff\Application;
use ConstanzeStandard\Fluff\Middleware\EndOutputBuffer;
use ConstanzeStandard\Fluff\RequestHandler\DelayHandler;
use Nyholm\Psr7\ServerRequest;
use Nyholm\Psr7\Response;
use Psr\Http\Message\ServerRequestInterface;
class Target
{
public function __construct(string $say)
{
$this->say = $say;
}
public function index(ServerRequestInterface $request, array $args)
{
return new Response(200, [], 'Hello '. $args['name']);
}
}
$handler = new DelayHandler('Target@index', ['name' => 'World'], 'Hello');
$app = new Application($handler);
$app->addMiddleware(new EndOutputBuffer());
$request = new ServerRequest('GET', '/');
$app->handle($request);
DelayHandler
初始化的第一个参数可以像 Handler
那样传递一个 callable
对象,也可以像上例那样,传递一个形如 类名称@方法名
的描述字符串,如果只有类名称的话,则会默认调用 __invoke
方法;第二个参数和 Handler
相同,一个用来传递额外信息的数组;后面可以接受任意个数的额外参数。
DelayHandler
会解析 类名称@方法名
的描述信息,然后初始化类,调用方法。额外的参数将在初始化时传入构造方法中,但如果第一个参数是 callable
对象则额外的参数会被忽略。
DelayHandler
在与 Dispatcher
配合使用时非常有用,它在面对多个类的选择时只做一次初始化,可以减少系统资源的消耗。
依赖注入 (DI Handler)
DiHandler
可以对类的方法,或可调用对象的参数进行解析,并进行依赖注入。DiHandler
必须与容器(Container)
配合使用。DiHandler
初始化的第一个参数是 Psr\Container\ContainerInterface
的实例;第二个参数是 类名称@方法名
的描述或 callable
对象;第三个参数是一个数组,为可调用对象提供额外的参数。
下例中使用的容器是 beige/psr-11
你可以通过 composer require beige/psr-11
命令进行安装。当然,你也可以选择自己熟悉的 PSR-11 容器,有关容器的概念请参阅 https://www.php-fig.org/psr/psr-11/。
use Beige\Psr11\Container;
use ConstanzeStandard\Fluff\Application;
use ConstanzeStandard\Fluff\Middleware\EndOutputBuffer;
use ConstanzeStandard\Fluff\RequestHandler\DiHandler;
use Nyholm\Psr7\ServerRequest;
use Nyholm\Psr7\Response;
use Psr\Http\Message\ServerRequestInterface;
class Service
{
public function sayHello($name)
{
return 'Hello ' . $name;
}
}
$container = new Container();
$container->set(Service::class, new Service());
$handler = new DiHandler($container, function (Service $service, $name) {
return new Response(200, [], $service->sayHello($name));
}, ['name' => 'World']);
$app = new Application($handler);
$app->addMiddleware(new EndOutputBuffer());
$request = new ServerRequest('GET', '/');
$app->handle($request);
如上例所示,DiHandler
的第三个参数的键名
与 callable
的参数名称必须一致,并且参数的声明不需要遵循任何顺序。如果对参数声明了类型,则 DiHandler
会从容器中查询与类型同名的依赖对象,并注入到参数中,所以必须在调用 Application::handle
方法之前将依赖对象(或依赖对象的 definition)放入容器中。
在使用 类名称@方法名
进行绑定时,DiHandler
也会对类的构造方法进行依赖注入,所以请不要将不可注入(没有声明类型,或容器中不存在的)的项 作为构造方法的参数。