依赖注入或实例化数据库 class 对象

Dependency Injection or instantiating database class object

这似乎是一个广泛的问题,但是依赖注入与在 __construct() 调用中实例化 class 的实际用途是什么?

我基本上在需要它的 classes 中像这样实例化我的数据库对象:

class Example {
    private $db;

    function __construct() {
        $this->db = db::instance();
    }
}

我过去使用过依赖注入,不知道是否可以简单地共享资源,以 Model.

中的以下示例为例
Class ExampleModel extends Model {

    function do_something() {
        $user = new User($db);
        $user->do_some_stuff();
    }
}

那么用什么比较有利呢?有没有性能相关的pros/cons?如果您需要对问题进行更多说明,请询问。


对依赖注入有很多正面和负面的看法:


对于任何感兴趣的人,这就是 db::instance() 的样子:

public static function instance() {
    if (!self::$instance) {
        $config = get_config();

        self::$instance = new self(
                $config['database']['host'], $config['database']['user'], $config['database']['pass'], $config['database']['db']
        );
    }
    return self::$instance;
}

总结我的评论 - 对我来说,如果您注入依赖项,那么 Example 不需要知道您注入的 class 是什么。如果您从 Example 中实例化 class 那么您需要确切地知道 class 是什么。

这是problem/benefit吗?取决于您、您的偏好和您的应用。我倾向于更抽象的方法。

例如,如果您执行了以下操作:

class Example {
    public function __construct(Injected $inj) {
        $this->db = $inj;
    }
}

...您可以看到您输入的提示是您期望 $inj 的内容。这可以是 $inj 直接是 class 的类型,也可以是 $inj 实现的接口 - 在这种情况下,您将知道 $inj 遵循一组您期望的说明。

举个例子:

interface Db {
    public function fetch();
    public function insert();
}

class MyDb implements Db {
    public function fetch() {
        // ...
    }
    public function insert() {
        // ...
    }
}

如果您在 Example class 中键入提示接口,您不需要知道 $injMyDb class,但它实现了 Db - 重要的部分是知道 class 将遵循一组定义的规则(接口),例如即会实现 fetch()insert() 函数。没关系实际 class - 你只需要内容。

class Example {
    public function __construct(Db $inj) {
        var_dump(get_class($inj)); // string(4) "MyDb"
    }
}

这就是注射及其好处的一个例子。直接实例化的等效项意味着您的 Example 需要了解 MyDb:

class Example {
    public function __construct() {
        $this->db = new MyDb; // implements Db, but you need to know exactly
                              // what the class is
    }
}

此方法消除了将 MyDb 更改为 YourDb 的灵​​活性,而无需更改 Example class.

同样,取决于您的情况。如果您的应用程序有可能更改或在组件内具有灵活性,您可能希望使用注入。如果它是相当静态的,那么你可以直接实例化。

我最后的评论是,当您对代码进行单元测试时,模拟注入的对象比直接实例化的对象要容易得多。