我应该在我的php项目中使用依赖注入吗?

时间:2012-01-19 21:32:24

标签: php oop dependency-injection

我最近了解了依赖注入的优点,但我想知道我是否应该在我的项目中使用它,因为我甚至不需要完整的mvc。现在我正在使用它,我意识到我写的每个页面都有额外的开销。例如......

    require_once '../../include/session.class.php';
    require_once '../../include/db.class.php';
    require_once '../../include/account.class.php';

    $objSession = new Session();
    $objDb      = new Db();
    $objAccount = new Account( $objSession, $objDb );

account.class.php

class Account {
    ...
    public function __construct( Session $objSession, Db $objDb ) {
        $this->session = $objSession;
        $this->db = $objDb;
    }
}

... Account类总是需要Db和Session,我只会有一个类。所以我的问题是,如果我在这种情况下使用DI,或者我应该使用......

account.class.php

require_once '../../include/session.class.php';
require_once '../../include/db.class.php';

class Account {
    ...
    public function __construct() {
        $this->session = new Session();
        $this->db = new Db();
    }
}

...

3 个答案:

答案 0 :(得分:6)

依赖注入与MVC无关。它非常擅长使单元测试更容易编写,最终我发现它让我真正考虑了我正在使用的资源以及该实现是否应该使用该资源。

我个人没有看到创建注入对象的危害,所以你有几行你必须创建一个对象?它告诉用户更多关于发生了什么。与魔术相比,我宁愿清晰。

就个人而言,我认为代码中的大部分混乱来自require语句。我会说自动加载器会解决一些问题。

我非常喜欢这个Google Clean Code Talk on DI。它帮助我更好地掌握了这个概念及其好处。

答案 1 :(得分:1)

您已经了解了依赖注入的优点。你为什么开始使用它?

是否因为能够将这些特定的依赖项替换为测试或不同的环境?它是否孤立并明确循环依赖链的顺序?

例如,假设为了测试目的而需要注入不同的类(DI的优点使我使用它)。没有DI,你如何处理?

查看您的帐户类。您可以使用if检查某些谓词testMode()来修改构造函数,也可以修改Db和Session构造函数,或者可以更改配置文件。无论你选择哪种非DI解决方案,你都可以吗?那么其他依赖项(电子邮件,记录器等)呢?您是否有任何外部系统接口,您应该模拟测试?

无论如何,答案可能是您在没有DI解决方案的情况下感到满意,并且您的应用程序足够小,可以在没有它的情况下进行管理。但无论如何,问自己这个问题很重要。

同样,将相同的提问线应用于DI的其他优点,这些优点促使您开始使用它。

顺便提一下,您在帐户中有一个Db实例,而在其他每个类中都有另一个实例吗?你能有一个实例吗? DI有助于此。你可以使用单例类,而不是通过总是注入相同的实例将它们编码为单例。

出于好奇,为什么要进行自己的依赖注入而不是使用DI库?使用DI的一半好处是它被其他人的实现干净地抽象出来。只需编写您需要的代码,让图书馆负责为您进行注射。这类似于drrcknlsn的建议,但没有编写DependencyInjectionContainer类的实际实现:

$ account = DependencyInjectionContainer :: build('Account');

并将其余部分搞定。

一个好的DI库应该看到Account的构造函数,意识到它需要一个Db和一个Session,然后进入构造函数链(在这种情况下,它结束于那里,因为它们都有空的构造函数)。这转换为具有与非DI情况相同数量的代码(加上构造函数的参数,减去对内部构造函数的调用,但顶部没有额外的废话),以及首先带给您DI的任何好处。

答案 2 :(得分:0)

发明了依赖注入容器来解决这个问题。考虑:

$account = DependencyInjectionContainer::build('Account');

DependencyInjectionContainer类将处理注入:

public static function build($class) {
    switch ($class) {
        case 'Account':
            $session = new Session();
            $db = new Db();
            return new Account($session, $db);

        // ...
    }
}