Php Slim Framework 3-如何将$logger注入路由控制器

Php Slim Framework 3-如何将$logger注入路由控制器,php,dependency-injection,slim,slim-3,Php,Dependency Injection,Slim,Slim 3,我使用的是slimframework3。我想将dependencies.php中定义的$logger注入路由器控制器类。下面是我做的,有没有更好的办法 routes.php $app->get('/test', function($request, $response, $args){ $controller = new AccountController($this->get('logger')); return $controller->test($request,

我使用的是slimframework3。我想将
dependencies.php
中定义的
$logger
注入路由器控制器类。下面是我做的,有没有更好的办法

routes.php

$app->get('/test', function($request, $response, $args){
  $controller = new AccountController($this->get('logger'));
  return $controller->test($request, $response, $args);
});
AccountController

class AccountController{

    private $logger;
    function __construct($logger){
        $this->logger = $logger;
    }

    public function test($request, $response, $args){
        $this->logger->info('i am inside controller');
        return $response->withHeader('Content-Type', 'application/json')->write('test');
    }
}
class AccountController
{
    protected $ci;

    //Constructor
    public function __construct(ContainerInterface $ci) 
    {
        $this->ci = $ci;
    }

    public function test($request, $response, $args)
    {
        $this->ci->get('logger')->info('i am inside controller');
        return $response->withHeader('Content-Type', 'application/json')->write('test');
    }
}
在Slim Framework 3文档中,使用路由控制器的正确方法应为:

$app->get('/test', 'AccountController:test');
但是,当我选择以这种更“优雅”的方式对路线控制器进行编码时,如何将
$logger
注入AccountController?

根据,您应该能够通过控制器内的容器访问记录器:

AccountController

class AccountController{

    private $logger;
    function __construct($logger){
        $this->logger = $logger;
    }

    public function test($request, $response, $args){
        $this->logger->info('i am inside controller');
        return $response->withHeader('Content-Type', 'application/json')->write('test');
    }
}
class AccountController
{
    protected $ci;

    //Constructor
    public function __construct(ContainerInterface $ci) 
    {
        $this->ci = $ci;
    }

    public function test($request, $response, $args)
    {
        $this->ci->get('logger')->info('i am inside controller');
        return $response->withHeader('Content-Type', 'application/json')->write('test');
    }
}
当您调用
$app->get('/test',AccountController:test'),Slim应自动将容器传递到
AccountController
的构造函数中

话虽如此,这与其说是伟大设计的一个例子,不如说是一个方便的特性。正如Rob Allen在他的回答中解释的那样,通过将控制器注入应用程序容器,而不是将容器注入每个控制器,您可以实现更好的模块化,从而更容易测试代码(如果您使用的是单元测试)


看看他的。例如,如果您看一下,您可以看到控制器类如何不再依赖于提供所有服务的神奇容器。相反,您可以在构造函数中显式声明每个控制器需要哪些服务。这意味着您可以更轻松地模拟测试场景中的各个依赖项。

为了使控制器更易于测试,您应该通过构造函数将记录器注入控制器

AccountController如下所示:

class AccountController
{
    protected $logger;

    public function __construct($logger) {
        $this->logger = $logger;
    }

    public function test($request, $response, $args){
        $this->logger->info('i am inside controller');
        return $response->withJson(['foo' => 'bar']);
    }
}
在index.php中设置如下:

$container = $app->getContainer();
$container[Logger::class] = function ($c) {
    $logger = new \Monolog\Logger('logger');
    return $logger;
};
$container[AccountController::class] = function ($c) {
    $logger = $c->get(Logger::class);
    return new AccountController($logger);
};

$app->get('/test', 'AccountController:test');

请注意,如果将format route callable设置为字符串
“class name”colon“method name”
,则Slim 3将在从DI容器提取控制器类后为您调用该方法。如果类名不是容器的注册密钥,那么它将实例化它并将容器传递给构造函数。

谢谢!我怎么会错过那条信息!我通过:function\uuu构造(Slim\container$ci)获得容器这不是将记录器注入控制器的正确方法。因为在本例中,您将注入容器本身。这不是正确的方法。我想你可以看看罗布的答案@是的,我在剩下的回答中提到了。嘿,谢谢你的回答。如果我有10个需要使用记录器的控制器,会发生什么?我创建了10个工厂,因为这些控制器通常具有其他依赖项,例如服务类或数据库映射器。