如何在简单的 php 函数中使用“依赖注入”,我应该打扰吗?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/2255771/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-25 05:44:38  来源:igfitidea点击:

How can I use "Dependency Injection" in simple php functions, and should I bother?

phpdependency-injectionparameter-passing

提问by Kzqai

I hear people talking about dependency injection and the benefit of it all the time, but I don't really understand it.

我一直听到人们谈论依赖注入及其好处,但我并不真正理解它。

I'm wondering if it's a solution to the "I pass database connections as arguments all the time" problem.

我想知道它是否是“我一直将数据库连接作为参数传递”问题的解决方案。

I tried reading wikipedia's entry on it, but the example is written in Java so I don't solidly understand the difference it is trying to make clear. ( http://en.wikipedia.org/wiki/Dependency_injection).

我尝试阅读维基百科关于它的条目,但该示例是用 Java 编写的,所以我不能完全理解它试图阐明的区别。(http://en.wikipedia.org/wiki/Dependency_injection)。

I read this dependency-injection-in-php article ( http://www.potstuck.com/2009/01/08/php-dependency-injection/), and it seems like the objective is to not pass dependencies to an object directly, but to cordon off the creation of an object along with the creation of it's dependencies. I'm not sure how to apply that in a using php functions context, though.

我读了这篇dependency-injection-in-php文章(http://www.potstuck.com/2009/01/08/php-dependency-injection/),似乎目标是不将依赖项传递给对象直接,但要封锁对象的创建以及它的依赖项的创建。不过,我不确定如何在使用 php 函数的上下文中应用它。

Additionally, is the following Dependency Injection, and should I bother trying to do dependency injection in a functional context?

此外,下面是依赖注入,我是否应该费心尝试在函数上下文中进行依赖注入?

Version 1: (the kind of code that I create, but don't like, every day)

版本1:(我每天都创建但不喜欢的那种代码)

function get_data_from_database($database_connection){
    $data = $database_connection->query('blah');
    return $data;
}

Version 2: (don't have to pass a database connection, but perhaps not dependency injection?)

版本 2 :(不必传递数据库连接,但也许不是依赖注入?)

function get_database_connection(){
    static $db_connection;
    if($db_connection){
        return $db_connection;
    } else {
        // create db_connection
      ...
    }
}

function get_data_from_database(){
   $conn = get_database_connection();
   $data = $conn->query('blah');
   return $data;
}

$data = get_data_from_database();

Version 3: (the creation of the "object"/data is separate, and the database code is still, so perhaps this would count as dependency injection?)

版本 3:(“对象”/数据的创建是分开的,而数据库代码是静止的,所以这可能算作依赖注入?)

function factory_of_data_set(){
    static $db_connection;
    $data_set = null;
    $db_connection = get_database_connection();
    $data_set = $db_connection->query('blah');
    return $data_set;
}

$data = factory_of_data_set();

Anyone have a good resource or just insight that makes the method and benefit -crystal- clear?

任何人都有一个很好的资源或只是洞察力,使方法和好处 - 晶莹剔透?

回答by Arkh

Dependency injection is a big word for "I have some more parameters in my constructor".

依赖注入是“我的构造函数中有更多参数”的大词。

It's what you did before the awfull Singleton wave when you did not like globals :

当你不喜欢 globals 时,这就是你在可怕的 Singleton 浪潮之前所做的:

<?php
class User {
    private $_db;
    function __construct($db) {
        $this->_db = $db;
    }
}

$db   = new Db();
$user = new User($db);

Now, the trick is to use a single class to manage your dependencies, something like that :

现在,诀窍是使用单个类来管理您的依赖项,如下所示:

class DependencyContainer 
{
    private _instances = array();
    private _params = array();

    public function __construct($params)
    {
        $this->_params = $params;
    }

    public function getDb()
    {
        if (empty($this->_instances['db']) 
            || !is_a($this->_instances['db'], 'PDO')
        ) {
            $this->_instances['db'] = new PDO(
                $this->_params['dsn'],
                $this->_params['dbUser'], 
                $this->_params['dbPwd']
            );
        }
        return $this->_instances['db'];
    }
}

class User
{
    private $_db;
    public function __construct(DependencyContainer $di)
    {
         $this->_db = $di->getDb();
    }
}

$dependencies = new DependencyContainer($someParams);
$user = new User($dependencies);

You must think you just another class and more complexity. But, your user class may need something to log messages like lot of other classes. Just add a getMessageHandler function to your dependency container, and some $this->_messages = $di->getMessageHandler()to your user class. Nothing to change in the rest of your code.

你一定认为你只是另一个类和更多的复杂性。但是,您的用户类可能需要像许多其他类一样记录消息。只需将 getMessageHandler 函数添加到您的依赖项容器,并将一些添加$this->_messages = $di->getMessageHandler()到您的用户类。其余代码无需更改。

You'll get lot of infos on symfony's doc

你会在symfony 的文档中得到很多信息

回答by jmoz

Your first example ISdependancy injection, you are injecting the dependency on the database object into the function.

你的第一个例子依赖注入,你将数据库对象的依赖注入到函数中。

Sarah has said this isn't, but imo it is, I believe she is thinking of dependency injection containers which are the next level up:

莎拉说这不是,但我认为是,我相信她正在考虑下一个级别的依赖注入容器:

http://components.symfony-project.org/dependency-injection/trunk/book/02-Dependency-Injection-Containers

http://components.symfony-project.org/dependency-injection/trunk/book/02-Dependency-Injection-Containers

回答by Sarah Happy

None of your examples look like dependency injection, version one is the closest though. Dependency injection is a technique used in object oriented programming, where the constructor of an object has arguments for the service objects it needs, and those service objects are passed in by the creator of the instance (which could be a factory, a test, or a dependency injection framework).

您的示例中没有一个看起来像依赖项注入,但第一个版本是最接近的。依赖注入是面向对象编程中使用的一种技术,其中对象的构造函数具有它需要的服务对象的参数,这些服务对象由实例的创建者(可以是工厂、测试或依赖注入框架)。

To get around your 'always passing the connection object' problem you may want to consider the template pattern. The template pattern is basically an abstract base class with the common part of a repeated code block, and abstract methods to allow for the variation between the instances of those repeated code blocks. Basically the base is a template of a block of code, and the abstract methods are the blanks to be filled in. I personally use the template method pattern to do my database resource control in Java.

要解决“始终传递连接对象”的问题,您可能需要考虑模板模式。模板模式基本上是一个抽象基类,具有重复代码块的公共部分,以及允许这些重复代码块实例之间变化的抽象方法。基本上base是一个代码块的模板,抽象方法是需要填充的空白。我个人在Java中使用模板方法模式来做我的数据库资源控制。

回答by Ben

I have done much searching on this topic myself (PHP Dependency Injection) and haven't found much to my liking. A lot has been written on the subject for other languages (Google Guice - http://code.google.com/p/google-guice/; Java Spring), but I couldn't find much available for PHP. Regardless of the language, however, the challenges are similar.

我自己对这个主题做了很多搜索(PHP 依赖注入),但没有找到太多我喜欢的。关于其他语言的主题已经写了很多(Google Guice - http://code.google.com/p/google-guice/;Java Spring),但我找不到太多可用于 PHP 的内容。然而,无论使用哪种语言,挑战都是相似的。

The three versions you list in your question are the typical approach. Version 3 is the closest to the direction in which I have seen the industry going. By shifting the responsibility of creating your dependent objects outside of your class, you are free to manipulate them as you please in your test code. However, the problem that I encountered with that approach is that you end up with long chains of dependent objects in your constructor that can potentially not even be used by the receiving object, but get passed through to an secondary dependent object. It gets messy and you lose knowledge of what is coming from where.

您在问题中列出的三个版本是典型的方法。第 3 版最接近我所看到的行业发展方向。通过将创建依赖对象的责任转移到类之外,您可以在测试代码中随意操作它们。但是,我在使用这种方法时遇到的问题是,您最终会在构造函数中得到一长串依赖对象,这些对象甚至可能不被接收对象使用,而是传递给辅助依赖对象。它变得一团糟,你不知道什么是从哪里来的。

The Dependency Container example by @Arkh and @mmmshuddup is a great start, but I nonetheless found limitations with that approach as well. The final solution upon which I arrived was a custom built solution modeled somewhat after the Cake Pattern popular in Scala. It allows you to pass a single dependency into each of your constructors AND it lets you define the default construction of the dependent objects perclass. This frees you from long dependency chains as well as losing control of the default implementations of your dependencies.

@Arkh 和 @mmmshuddup 的 Dependency Container 示例是一个很好的开始,但我仍然发现这种方法存在局限性。我得到的最终解决方案是一个自定义构建的解决方案,该解决方案在某种程度上模仿了 Scala 中流行的 Cake Pattern。它允许您将单个依赖项传递到每个构造函数中,并允许您定义每个类的依赖对象的默认构造。这使您摆脱了长依赖链以及失去对依赖项的默认实现的控制。

I called the system Diesel and I've been really happy with it. I published the code on github for anyone interested. You can get to it from the blog I wrote on the subject, which describes the basic usage as well as goes into more detail on your question. http://developers.blog.box.com/2012/02/15/introducting-diesel-php-dependency-injection/

我将系统称为 Diesel,对此我感到非常满意。我在 github 上为任何感兴趣的人发布了代码。您可以从我写的关于该主题的博客中获取它,该博客描述了基本用法并详细介绍了您的问题。http://developers.blog.box.com/2012/02/15/introducting-diesel-php-dependency-injection/

回答by Jerome WAGNER

Dependency Injection is the idea of removing the dependency between 2 components in order to focus on why they are dependent.

依赖注入的想法是去除 2 个组件之间的依赖关系,以便专注于它们为何依赖。

Imagine you have a component A that needs to use the services of another component B.

假设您有一个组件 A 需要使用另一个组件 B 的服务。

If you hardcode the existence of B inside A, then you will be stuck when you will want A to use the sames services, but implemented by another component.

如果您在 A 中硬编码 B 的存在,那么当您希望 A 使用相同的服务但​​由另一个组件实现时,您将陷入困境。

So usually, you define a service interface that B and C will implement, and you make sure that when you use A, you feed it with objects compatible with the needed interface.

所以通常,你定义一个 B 和 C 将实现的服务接口,并确保当你使用 A 时,你向它提供与所需接口兼容的对象。

In your case, you might consider that your interface is a service on which you can make a query.

在您的情况下,您可能认为您的接口是一个可以进行查询的服务。

Your first case is the one that is the closer to the idea of Dependency Injection.

您的第一个案例是更接近依赖注入的想法的案例。