如何构建PHP依赖注入容器 [英] How to build a PHP Dependency Injection Container

查看:118
本文介绍了如何构建PHP依赖注入容器的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I've recently learned about the advantages of using Dependency Injection (DI) in my PHP application. However, I'm still unsure how to create my container for the dependencies, or whether I should be using DI at all for the online forum that I'm building.

以下代码是我根据从在此处学到的示例制作的DI容器的版本。 a>。

The following code is my version of the DI container I have made based on the example I learned from here .

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();

我有几个问题:

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

1) Where should I instantiate my injected dependencies, such as $database, $session, etc? Would it be outside the container class, or inside the container's constructor.

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

2) What if I need to create a multiple instances of the User class inside other classes? I can't inject the previously instantiated $user object because that instance is already being used. However, creating the multiple User instances inside of another class would violate the rules of DI. For example:

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();
        }
    }
}   

3)我想知道如果我什至应该采用DI,那么我就必须重写所有先前的代码。我以前一直依赖在我的initialize.php中实例化的全局变量,该变量包含在我的所有文件中。

3) I'm wondering if I should even adopt DI, knowing that I have to rewrite all of my previous code. I've previously been relying on global variables that I instantiate in my initialize.php, which is included in all my files.

在我看来,DI会产生大量开销,并且在某些情况下它无法使用(例如在我的第二个示例中)。以下站点来自开发人员,他引用了许多不使用DI的充分理由。他的论点有什么优点吗?还是我使用DI错误?
选中此链接

It seems to me that DI creates a lot of overhead and there are situations where it is unusable (as in my #2 example). The following site is from a developer who cites many good reasons not to use DI. Does his arguments have any merit? Or am I just using DI wrong? check this link.

推荐答案


我应该在哪里实例化注入的依赖项,例如$ database,$ session等?

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

Ideally your database connection and session would be bootstrapped in. Proper DI requires an instance of a base object for which everything is registered into. So taking your IOC class as an example you need to make an instance of it ($ioc = new IOC();) then you need some kind of service provider class say

$ioc->register('database', new DatabaseServiceProvider($host, $user, $pass))

现在,每次您想连接数据库时,只需传递 $ ioc -> get('database'); 一个非常粗糙的示例,但是我认为您可以看到,其想法基本上是将所有内容存储在注册表中,并且没有任何静态绑定,这意味着您可以创建 $ ioc 具有完全不同的设置,可以轻松创建连接以说出不同的数据库以进行测试。

Now every time you want a connection to the database you just need to pass in $ioc->get('database'); a very rough example but I think you can see the idea is basically to store everything inside a registry and nothing is statically binded meaning you can create another instance of $ioc with totally different settings making it easy to create connections to say a different database for testing purposes.


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

这是一个常见问题并且有多种不同的解决方案。首先,您的DI应该显示已登录用户和仅一个用户之间的区别。您可能想要注册您的登录用户,而不只是任何用户。使您的用户类别正常并使用

This is a common issue and there are multiple different solutions. Firstly your DI should show the difference between logged in user and just a user. You would probably want to register your logged in user but not just any user. make your user class just normal and use

$ioc->register('login-user', User::fetch($ioc->get('database'), $user_id));

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

so now $ioc->get('login-user') returns your logged in user. You can then use User->fetchAll($ioc->get('database')); to get all your users.


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

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

If you need to rewrite all your code to use DI you shouldn't probably do it. Maybe look into making a new project and work in some of your old code if you have the time. If your codebase is large I would recommend looking into breaking it down into smaller projects and using RESTFUL apis for getting and saving data. Good examples of writing APIs would be for putting your forum search into its own application /search/name?partial-name=bob would return all users with the word bob in it. you could build it up and make it better over time and use it in your main forum

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

I hope you understand my answers but if you need any more info let me know.

这篇关于如何构建PHP依赖注入容器的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆