我听到人们一直在谈论依赖注入和它的好处,但我并不理解它。
我想知道它是否是“我一直将数据库连接作为参数传递”问题的解决方案。
我试过阅读维基百科上的条目,但这个例子是用Java编写的,所以我不能完全理解它试图弄清楚它的区别。 (http://en.wikipedia.org/wiki/Dependency_injection)。
我读了这篇依赖注入的php文章(http://www.potstuck.com/2009/01/08/php-dependency-injection/),似乎目标是不直接将依赖项传递给对象,而是封锁对象的创建以及创建它的依赖关系。我不知道如何在使用php函数上下文中应用它。
此外,还有以下依赖注入,我是否应该尝试在功能上下文中进行依赖注入?
版本1 :(我创建的代码类型,但每天都不喜欢)
function get_data_from_database($database_connection){
$data = $database_connection->query('blah');
return $data;
}
版本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();
版本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();
任何人都有良好的资源或只是洞察力,使方法和利益 - 水晶 - 清楚?
答案 0 :(得分:75)
依赖注入是“我在构造函数中有更多参数”的重要词汇。
当你不喜欢全局变量时,这就是你在糟糕的单身人士之前所做的事情:
<?php
class User {
private $_db;
function __construct($db) {
$this->_db = $db;
}
}
$db = new Db();
$user = new User($db);
现在,诀窍是使用单个类来管理您的依赖项,类似于:
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);
你必须认为你只是另一个阶级而且更复杂。但是,您的用户类可能需要一些东西来记录许多其他类的消息。只需将getMessageHandler函数添加到依赖项容器中,并将一些$this->_messages = $di->getMessageHandler()
添加到您的用户类。其余代码无需更改。
答案 1 :(得分:13)
您的第一个示例 IS 依赖注入,您将数据库对象的依赖注入到函数中。
莎拉已经说过这不是,但就是这样,我相信她正在考虑下一级别的依赖注入容器:
答案 2 :(得分:7)
您的示例都不像依赖注入,第一版是最接近的。依赖注入是一种用于面向对象编程的技术,其中对象的构造函数具有所需服务对象的参数,并且这些服务对象由实例的创建者传入(可以是工厂,测试或依赖注入框架)。
要解决“始终传递连接对象”问题,您可能需要考虑模板模式。模板模式基本上是具有重复代码块的公共部分的抽象基类,以及允许这些重复代码块的实例之间的变化的抽象方法。基本上,base是一个代码块的模板,抽象方法是要填充的空白。我个人使用模板方法模式在Java中进行数据库资源控制。
答案 3 :(得分:2)
我自己在这个主题上做了很多搜索(PHP依赖注入)并且没有找到我喜欢的内容。关于其他语言(Google Guice - http://code.google.com/p/google-guice/; Java Spring)已经写了很多关于这个主题的文章,但我找不到很多可用于PHP的文章。然而,无论语言如何,挑战都是相似的。
您在问题中列出的三个版本是典型方法。版本3最接近我看到行业发展的方向。通过将创建依赖对象的责任转移到课堂之外,您可以在测试代码中随意操作它们。但是,我在这种方法中遇到的问题是,您最终会在构造函数中使用长链依赖对象,这些对象甚至可能无法被接收对象使用,但会被传递给辅助依赖对象。它变得混乱,你不知道从哪里来的东西。
@Arkh和@mmmshuddup的Dependency Container示例是一个很好的开始,但我仍然发现了这种方法的局限性。我到达的最终解决方案是一个定制的解决方案,在Scala中流行的Cake Pattern之后有点模仿。它允许您将单个依赖项传递给每个构造函数,并允许您定义依赖对象 per 类的默认构造。这使您免于长依赖链以及失去对依赖项的默认实现的控制。
我打电话给柴油系统,我对它非常满意。我在github上为任何感兴趣的人发布了代码。您可以从我在该主题上撰写的博客中了解它,该博客描述了基本用法,并详细介绍了您的问题。 http://developers.blog.box.com/2012/02/15/introducting-diesel-php-dependency-injection/
答案 4 :(得分:2)
依赖注入是消除两个组件之间依赖关系的想法,以便关注它们依赖的原因。
想象一下,你有一个组件A需要使用另一个组件B的服务。
如果您在A中硬编码B的存在,那么当您希望A使用相同的服务但由另一个组件实现时,您将陷入困境。
通常,您定义B和C将实现的服务接口,并确保在使用A时,使用与所需接口兼容的对象来提供它。
在您的情况下,您可能会认为您的界面是可以进行查询的服务。
您的第一个案例是更接近依赖注入概念的案例。