使用依赖注入创建实例?

时间:2018-02-12 19:18:21

标签: php dependency-injection

我正在尝试将DI应用到我的应用程序中。下面是我的路由片段,每个路由都有自己的控制器,里面有一个方法来返回视图。

$router->addRoute('GET', '/', ['App\Controllers\Frontend\Guest\LoginController', 'getView']);


假设我有多个控制器,我必须传递一个Template类的实例。

class LoginController {

    private $template;

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

    public function getView() {
        $this->template->renderTemplate('index.html');
    }

}


我使用我的Template类与Twig交互,告诉它该做什么。

class Template {

    private $environment;

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

    public function render($template, array $vars) {
        return $this->environment->render($template, $vars);
    }

}

现在,我遇到的问题是我应该在哪里创建这些控制器的实例?当然,我不只是为我的每个控制器创建一个实例,这会变得混乱,对吗?

任何人都可以给我一些建议,我是DI的新手。

2 个答案:

答案 0 :(得分:3)

您正在寻找的内容称为依赖注入容器。我使用的那个Dice使用Reflection来构建你的类图,并且有一些功能可以让你的生活更轻松(缓存实例,共享实例(对数据库连接很有用)等等)。

基本上,它会从您提供给它的类开始查找所有依赖项,并根据需要创建它们。在您的示例中,在FrontController(或您作为应用程序的入口点使用的任何内容)中,您可以执行以下操作:

<?php

$dice = new \Dice\Dice;

// use your router to pick a controller and then
$controller = $dice->create($controllerChosenByRouter);

就是这样,Dice将实例Twig_Environment实例TemplateTemplate实例LoginController实例$controller构建,你可以按照你的意愿使用它。

这当然与只有类型提示的依赖关系一样。如果您的课程中有其他参数,请参阅构造函数,您可以使用规则来传递它。例如,假设您的LoginController也需要用户名

public function __construct(Template $template, $username);

然后,您可以使用constructParams规则来设置Dice应该设置为该参数的内容:

<?php
$rule = [
    "constructParams" => ["yixoco"],
];
$dice->addRule("LoginController", $rule);

此外,如果您需要将规则添加到您未直接实例化的类中,您也可以将shared设置为true,并且每次都会使用该实例它需要,所以它将使用您提供的确切参数:

$rule = [
    "constructParams" => [true], // setting cache to true
    "shared" => true,
];
$dice->addRule("Twig_Environment", $rule);
$dice->create("Twig_Environment");

现在,只要Dice需要,Twig_Environment参数设置为cache的{​​{1}}实例就会被使用。

看一下这些文档,它有很多功能可以让您的应用更加灵活。当然会加载更多内容,例如AuyrinPHP-DIPimple以及框架捆绑在一起的内容。如果你想对它进行更多研究,Here's是速度的基准。他们都有自己的做事方式,所以一定要仔细阅读,以便选择你最喜欢的,最符合你需求的那个!

答案 1 :(得分:0)

处理这个问题的一种巧妙方法是考虑你的控制器本身就是依赖。

因此,您可以(并且应该)将您的控制器注册到依赖注入容器中的任何其他服务。

现在更大的问题是如何让它们再次从容器中取出。一般来说,不鼓励将容器本身注入任何东西,因为它很快就会从无辜的依赖注入容器转变为邪恶的混蛋兄弟服务定位器。

这里有一个例外,就是你的路由器。根据经验,当您注入容器以获取依赖项时,出现问题。

然而,路由器对控制器没有依赖性,因此“允许”使用依赖注入容器来生成控制器。

有关更多信息和一些示例,请参阅"recommended usage" section of the PSR-11 (container) meta document