如何构建PHP依赖注入容器

Ano*_*ous 13 php dependency-injection

我最近了解到在我的PHP应用程序中使用依赖注入(DI)的优点.但是,我仍然不确定如何为依赖项创建容器,或者我是否应该在我正在构建的在线论坛中使用DI.

以下代码是我根据我从这里学到的例子制作的DI容器的版本.

class ioc {

   var $db;
   var $session;
   var $user_id;

   static function newUser(static::$db, static::$user_id) {
      $user = new User($db, $user_id);
      return $user;
   }

   static function newLogin(static::$db, static::$session) {
      $login = new Login($db, $session);
      return $login;
   }

}

$user = ioc::newUser();
$login = ioc::newLogin();
Run Code Online (Sandbox Code Playgroud)

我有几个问题:

1)我应该在哪里实例化我注入的依赖项,例如$ database,$ session等?它是在容器类之外,还是在容器的构造函数内部.

2)如果我需要在其他类中创建User类的多个实例,该怎么办?我无法注入先前实例化的$ user对象,因为该实例已被使用.但是,在另一个类中创建多个User实例会违反DI规则.例如:

class Users {

    function __construct($db, $user_id) {
        $this->db = $db;
        $this->user_id = $user_id;
    }

    function create_friends_list() {
        $st = $this->$db->prepare("SELECT user_id FROM friends WHERE user_id = $this->user_id");
        $st->execute();
        while($row = $st->fetch()) {
            $friend = ioc::newUser($row['user_id']);
            $friend->get_user_name();
            $friend->get_profile_picture();
        }
    }
}   
Run Code Online (Sandbox Code Playgroud)

3)我想知道我是否应该采用DI,因为我知道我必须重写所有以前的代码.我以前一直依赖于我在我的initialize.php中实例化的全局变量,它包含在我的所有文件中.

在我看来,DI会产生大量开销,并且在某些情况下它无法使用(如我的#2示例中所示).以下网站来自开发人员,他列举了许多不使用DI的好理由.他的论点有什么价值吗?或者我只是使用DI错误? 检查此链接.

小智 7

我应该在哪里实例化我注入的依赖项,例如$ database,$ session等?它是在容器类之外,还是在容器的构造函数内部.

理想情况下,您的数据库连接和会话将被引导.正确的DI需要一个基础对象的实例,其中所有内容都已注册到该实例中.所以以你的IOC类为例,你需要创建一个它的实例($ioc = new IOC();)然后你需要某种服务提供者类说

$ioc->register('database', new DatabaseServiceProvider($host, $user, $pass))
Run Code Online (Sandbox Code Playgroud)

现在,每当你想要连接到数据库时,你只需要传递$ioc->get('database');一个非常粗略的例子,但我认为你可以看到这个想法基本上是将所有内容存储在一个注册表中,没有任何东西是静态绑定意味着你可以创建另一个$ioc完全实例不同的设置可以轻松创建连接,以便为测试目的说出不同的数据库.

如果我需要在其他类中创建User类的多个实例,该怎么办?我无法注入先前实例化的$ user对象,因为该实例已被使用.但是,在另一个类中创建多个User实例会违反DI规则.

这是一个常见问题,有多种不同的解决方案.首先,你的DI应该显示登录用户和用户之间的区别.您可能希望注册登录用户,但不仅仅是注册用户.使您的用户类正常并使用

$ioc->register('login-user', User::fetch($ioc->get('database'), $user_id));
Run Code Online (Sandbox Code Playgroud)

所以现在$ioc->get('login-user')返回您登录的用户.然后,您可以使用它User->fetchAll($ioc->get('database'));来获取所有用户.

我想知道我是否应该采用DI,因为我知道我必须重写所有以前的代码.我以前一直依赖于我在我的initialize.php中实例化的全局变量,它包含在我的所有文件中.

如果您需要重写所有代码以使用DI,那么您不应该这样做.如果您有时间,也许可以考虑制作一个新项目并使用一些旧代码.如果您的代码库很大,我建议您将其分解为较小的项目,并使用RESTFUL apis来获取和保存数据.编写API的好例子是将您的论坛搜索放入自己的应用程序/搜索/名称中?partial-name = bob将返回所有用户中包含单词bob的用户.你可以建立它并随着时间的推移使它更好,并在你的主论坛中使用它

我希望您理解我的答案,但如果您需要更多信息,请告诉我.


小智 1

而不是 init.php 中的全局变量定义您的对象,例如:

ioc::register('user', function() {
 return new User();
});
Run Code Online (Sandbox Code Playgroud)

并在您的 create_friends_list 方法中使用:

ioc::get('user')->newUser($user_id);
Run Code Online (Sandbox Code Playgroud)

这是一个非常简单的实现。查看: http://net.tutsplus.com/tutorials/php/dependency-injection-huh/ ?search_index=2

或者

http://net.tutsplus.com/tutorials/php/dependency-injection-in-php/?search_index=1

了解更多信息。