正在使用联盟/路由将容器注入控制器


Injecting container to controller with league/route

我正在使用联盟/路由,我想将我的容器注入控制器。这是我已经拥有的:

提供RouteCollection:

$this->getContainer()->share('route', function () {
    $route = require $this->getContainer()->get('baseDir').'/config/routes.php';
    return $route;
});

baseDir/config/routes.php:

<?php
use League'Route'Strategy'ParamStrategy;
use League'Container'ReflectionContainer;
$routes = (new 'League'Route'RouteCollection)
    ->setStrategy((new ParamStrategy)->setContainer(new ReflectionContainer));
    // The line above is here because ParamStrategy otherwise throws
    // Uncaught exception 'RuntimeException' with message 'To use the parameter strategy,
    // the container must implement the (::call) method.
$routes->get('/', 'Controller'PostController::index');
return $routes;

我的前控制器:

/** @var RouteCollection $route */
$route = $this->getContainer()->get('route');
/** @var ServerRequest $request */
$request = $this->getContainer()->get('request');
/** @var Response $response */
$response = $this->getContainer()->get('response');
/** @var SapiEmitter $emitter */
$emitter = $this->getContainer()->get('emitter');
$response = $route->dispatch($request, $response);
$emitter->emit($response);

我不知道应该在哪里调用控制器对象上的setContainer方法,因为它只存在于$route->dispatch($request, $response);中。将容器注入控制器的正确方法是什么?

这里首先有几点。

  1. 将容器注入控制器是服务位置。这被认为是反模式(http://ralphschindler.com/2012/10/10/di-dic-service-locator-redux是DI和SL之间区别的一个很好的解释)
  2. 在您的示例中,您在路由集合上显式设置了一个反射容器,这意味着它将专门尝试通过反射而不是根据您可能设置的任何定义来解析依赖关系,因为原始容器正在被覆盖

如果你坚持在控制器中使用容器,你可以在容器上使用一个屈折符来在每个控制器中实现这一点。http://container.thephpleague.com/inflectors/-通过使用此链接中的方法,您可以让控制器实现ContainerWareInterface,并且每当路由器解析其中一个控制器时,您都可以让容器调用在主容器中传递的setContainer方法。

希望这能有所帮助,我目前正在度假,所以不能给出代码示例,但我会在回来后编辑这个答案。