如何实现依赖注入容器和依赖注入

时间:2014-03-05 01:21:41

标签: php design-patterns dependency-injection

我想知道如何使用php(用于研究)实现依赖注入容器。我得到了依赖注入的概念,我可以实现它,但我只能考虑到php框架的控制器。

意味着整个实例化,注入等都发生在控制器中。像

       class SampleController{

       public function action1(){
            $sample_object = new ObjectToInject();
            $dependent_object = new DependentObject($sample_object);
            $dependent_object->doSomething();
            ...
            etc
       }


      }

现在我所说的是如果逻辑变得更复杂,控制器会变得臃肿。我知道我的控制器变得臃肿,这是不是意味着它仍然不那么可维护?

问题:

  1. 我的假设是否正确,控制器现在拥有所有逻辑?
  2. 那么依赖注入容器的用途是什么?这与他在article中所说的引导程序相同吗?
  3. 请解释Symfony2依赖注入容器的功能。
  4. 请使用php。给我一个具体的Dependency Injection Container示例。
  5. 我是否正确,在单元测试中,只需测试依赖类,不需要测试独立类。
  6. 如果我的问题含糊不清,请纠正我。 感谢

2 个答案:

答案 0 :(得分:4)

这是一个非常重要的问题。要快速回答您的观点:

(1)不。这不正确。虽然您必须在某处进行布线,但它不应该在您的控制器中。您的控制器应仅接收完成其工作所需的完全构建的对象。不要给他们超过他们需要的东西。 例如:

例如

class UserController 
{
    public function __construct(UserRepository $UserRepository)
    {
        $this->UserRepository = $UserRepository;
    }

    public function showUser($id)
    {
        $User = $this->UserRepository->find($id);
    }
}

请注意UserController只有UserRepository作为依赖项? UserRepository同时可能看起来像这样:

class UserRepository
{
    protected $registry = array();

    public function __construct(UserFactory $UserFactory, UserMapper $UserMapper)
    {
        $this->UserFactory = $UserFactory;
        $this->UserMapper = $UserMapper;
    }

    public function find($id)
    {
        if (isset($this->registry[$id]) {
            return $this->registery[$id];
        }

        $User = $this->UserMapper>find($id);
        $this->registry[$User->id] = $User;
        return $User;
    }

    public function findOrNew($id)
    {
        if (!$User = $this->UserMapper->find($id)) {
            $User = $this->UserFactory->make(array('id' => $id));
        }

        return $User;
    }
}

UserController UserFactory如果不直接需要UserMapperUserRepository个对象,则应该不知道它们。此外,您的DataAccessLayer不应该知道注入UserMapper的{​​{1}}。 UserMapper也不需要知道DataAccessLayer依赖于PDOConnection对象而不是其他对象。

(2)容器的使用是做你不应该在控制器中做的事情:连接你所有的依赖关系。了解DI容器及其工作原理的最简单,最简单的方法是下载并使用Pimple。它是一个非常简单,直接的DI容器,它有很好的文档记录:https://github.com/fabpot/Pimple

(3)这是一个很大的话题。 Symfony是Pimple的更高级版本。我建议学习Pimple,然后阅读Symfony的文档并查看他们使用的示例。还可以查看Laravel's,甚至是PHP-DI https://github.com/mnapoli/PHP-DI

(4)和以前一样见疙瘩:https://github.com/fabpot/Pimple

(5)只要有测试内容,您应该努力测试所有代码逻辑。据推测,应用程序中的每个方法/函数/类都 ,因此您应该测试它正在做它应该做的事情。你不必做的是测试它的任何依赖都在做它们应该做的事情,因为你可能正在测试它们。您相信传入一个类或方法的数据已经过测试,然后您只测试新类/方法要执行的操作。

但同样,我强烈建议学习Pimple,然后尝试像PHP-DI这样的东西,看看自动反射和自动解析依赖关系是如何工作的。最好的方法就是让自己沉浸在各种容器中,并与它们一起玩耍。

答案 1 :(得分:1)

实例化依赖关系不是“逻辑”,它只是配置。

AmgLauncher写了一个很好的答案,我想提供一个更简单的答案:控制器与服务无异。您应该在控制器上使用依赖注入,就像服务一样。

问题在于:Symfony不鼓励(至少通过他们的文档)。不要盲目跟随Symfony的DIC文档。

所以最后,问题是:但是如果它有依赖关系,那么构建我的控制器的是什么/谁?

这是容器的工作。容器将构建您的控制器和所有服务。问题是一些框架不能以这种方式工作。在Symfony 2中,有一个选项:Controllers as services

如果您要使用Pimple,则必须编写创建所有控制器的所有代码。那是无用/无聊的代码。疙瘩不太适合。

正如AgmLauncher建议的那样,还要看PHP-DI,例如this guide about how to write controllers。我还建议您阅读What is a DI container and how it works的简单介绍。 (免责声明:我是PHP-DI的维护者)