这篇文章是关于一般依赖关系注入和在PHP中实现依赖注入容器系列的第一部分。

今天我不会谈论容器然而我想以一些具体的示例介绍依赖注入的概念希望说明尝试去解决问题和它给开发者带来的好处。如果你已经知道依赖注入的概念你可以略过本文等待下一篇。

依赖注入或许是我所知道的最简单的设计模式之一。或许你已经使用过依赖注入。但它是解释最困难的一个。我认为部分原因在于大多数介绍依赖注入的时候使用了没有意义的示例。我试图想出更符合PHP世界的例子由于PHP这种语言主要是用来做WEB开发的让我们举一个简单的WEB例子。

为了克服HTTP协议的无状态性web应用程序需要一种方法来存储web请求之间的用户信息。当然通过使用一个cookie或者甚至更好的方式通过使用PHP内置的会话机制(session)实现是非常简单的。

$_SESSION['language'] = 'fr';

上面的代码中用语言会话变量存储用户的语言。因此针对同一个用户的后续请求在超全局变量$_SESSION数组中的语言是有效的。

$user_language = $_SESSION['language'];

在面向对象的世界中依赖关系注入才有意义让我们假设我们有一个SessionStorage 类封装了PHP的会话机制

class SessionStorage

{

function __construct($cookieName = 'PHP_SESS_ID')

{

session_name($cookieName);

session_start();

}

function set($key, $value)

{

$_SESSION[$key] = $value;

}

function get($key)

{

return $_SESSION[$key];

}

// ...

}

... 和一个提供了更高级别接口的用户类

class User

{

protected $storage;

function __construct()

{

$this->storage = new SessionStorage();

}

function setLanguage($language)

{

$this->storage->set('language', $language);

}

function getLanguage()

{

return $this->storage->get('language');

}

// ...

}

这些类是足够简单的使用User类相比更容易

$user = new User();

$user->setLanguage('fr');

$user_language = $user->getLanguage();

全部都很好...直到你想要更多的灵活性。如果你想要修改实例会话cookie的名称下面是一些随机的可能性

·在User类里面是硬编码的名称在他的SessionStorage 构造函数中:class User

{

function __construct()

{

$this->storage = new SessionStorage('SESSION_ID');

}

// ...

}

在User类的外面定义一个常量

class User

{

function __construct()

{

$this->storage = new SessionStorage(STORAGE_SESSION_NAME);

}

// ...

}

define('STORAGE_SESSION_NAME', 'SESSION_ID');

添加会话的名称session name作为User类的构造函数的参数

class User

{

function __construct($sessionName)

{

$this->storage = new SessionStorage($sessionName);

}

// ...

}

$user = new User('SESSION_ID');

为存储类SessionStorage添加一个选项数组

class User

{

function __construct($storageOptions)

{

$this->storage = new SessionStorage($storageOptions['session_name']);

}

// ...

}

$user = new User(array('session_name' => 'SESSION_ID'));

所有的这些选择都是相当糟糕的。在User类中的硬编码会话名称session name并没有真正解决问题你不能轻易改变想法以后而无需再次更改User类。使用一个常量之所以糟糕的因为User类现在依赖一个常量被设置。传递会话名称session name作为一个参数或者作为一个选项数组是或许是最好的解决方法但它仍然很糟糕。用不相关的参数给对象本身打乱了User类构造函数的参数。

但是仍然有问题不能被解决我怎么才能更改SessionStorage 类呢例如为了方便测试将它替换为一个假对象。或者也许是因为你想要在数据库表中或者内存中存储会话sessions。当前实现是不可能的除非你修改User类。加入依赖注入而不是在User类里面建立SessionStorage 对象让我们在User对象通过传递一个构造参数注入SessionStorage对象

class User

{

function __construct($storage)

{

$this->storage = $storage;

}

// ...

}

这就是依赖注入。仅此而已使用User类现在多了一点包括你首先需要建立SessionStorage 对象

$storage = new SessionStorage('SESSION_ID');

$user = new User($storage);

现在配置会话存储对象session storage object是非常简单的和替换会话存储类也是非常容易。并且由于关注点的分离User类没有改变一切都是可能的。

“依赖注入是其中的组件通过他们的构造器、方法、或者直接到字段的方式”给与他们的依赖关系。

至于其他的设计模式依赖注入也有一些反模式。Pico Container website介绍了其中的一些。

依赖注入不局限于构造函数注入:

·构造器注入:

class User

{

function __construct($storage)

{

$this->storage = $storage;

}

// ...

}

·Setter注入:

class User

{

function setSessionStorage($storage)

{

$this->storage = $storage;

}

// ...

}

·属性注入:

class User

{

public $sessionStorage;

}

$user->sessionStorage = $storage;

作为经验法则构造器所需要的依赖关系是最好的就像在我们的例子中setter注入最适合可选的依赖关系比如像一个缓存实例对象。如今最现代化的PHP框架大量使用了依赖注入提供了一组解耦但内聚的组件。

// symfony: A constructor injection example

$dispatcher = new sfEventDispatcher();

$storage = new sfMySQLSessionStorage(array('database' => 'session', 'db_table' => 'session'));

$user = new sfUser($dispatcher, $storage, array('default_culture' => 'en'));

// Zend Framework: A setter injection example

$transport = new Zend_Mail_Transport_Smtp('smtp.gmail.com', array(

'auth'=> 'login',

'username' => 'foo',

'password' => 'bar',

'ssl'=> 'ssl',

'port'=> 465,

));

$mailer = new Zend_Mail();

$mailer->setDefaultTransport($transport);

如果你有兴趣学习更多关于依赖注入我强烈建议你阅读Martin Fowler introduction或者优秀的Jeff More presentation。你还可以去看看我去年给依赖注入做的介绍presentation在这篇文章中谈论的在里面讲了更多在例子上的细节。

今天就到这了。我希望你现在对依赖注入的概念有一个更好的理解。在本系列的下一篇文章我会谈谈依赖注入的容器。

python依赖注入_什么是依赖注入?相关推荐

  1. java什么是依赖注入_什么是依赖注入?

    转自 https://blog.csdn.net/coding_1994/article/details/80634810,这位作者写的很清晰. Spring 能有效地组织J2EE应用各层的对象.不管 ...

  2. java 依赖倒置_设计模式之三依赖倒置原则(DIP)

    依赖倒置(Dependence Inversion Principle,DIP) High level modules should not deppend oupon low level modul ...

  3. 反引号注入_什么是 SQL 注入?

    (给ImportNew加星标,提高Java技能) 转自:Java程序员联盟 文章目录: 何谓SQL注入? SQL数据库操作示例 SQL数据库注入示例 如何防止SQL注入问题 SQL数据库反注入示例 何 ...

  4. mysql dns 注入_数据库DNSLog外带注入-总结

    sql注入中利用的骚姿势你又知道几个? DNSLog外带注入和DNSlog带外注入?(OOB) 其实是一样的,叫法不同!本人还是习惯叫外带注入,自我感觉,比较顺口 为什么需要外带注入? 当我们对一个数 ...

  5. python依赖注入_如何做依赖注入python方式?

    这一切都取决于情况.例如,如果您使用依赖注入来进行测试,所以您可以轻松地嘲笑某些内容 – 您可以经常放弃注入:您可以嘲笑您将注入的模块或类: subprocess.Popen = some_mock_ ...

  6. java模块依赖关系_链接模块依赖关系未解决

    我正面临与 npm link 相关的问题 这是在本地发布模块并在其他角度应用程序中使用它们的情况 . 我有2个应用程序 1) app-core (published locally) 2) app-m ...

  7. java代码防止sql注入_动态Java代码注入

    java代码防止sql注入 在本文中,我们将研究如何将Java代码动态加载到正在运行的jvm中. 该代码可能是全新的,或者我们可能想更改程序中某些现有代码的功能. (在开始之前,您可能想知道为什么到底 ...

  8. mysql宽字节注入_转宽字节注入详解

    在mysql中,用于转义的函数有addslashes,mysql_real_escape_string,mysql_escape_string等, 还有一种情况是magic_quote_gpc,不过高 ...

  9. jsp mysql 注入_由Jsp+Mysql注入到root权限的全程展 【好久没有安全类文章了,转一篇看看】...

    由Jsp+Mysql注入到root权限的全程展 最近有点空闲,所以写点垃圾文章来消磨一下时间.文中没有什么技术含量,如果要转载,请注明作者并保持文章的完整. 很多人可能都知道asp,php的编程要防止 ...

最新文章

  1. zabbix之日志文件监控
  2. 这个对标苹果的微软实体店,开了十一年之后,现在要永久关闭了
  3. Delphi从Internet下载文件
  4. 2021算法竞赛入门班第十节课【字符串】练习题
  5. 7-4 递增序列 (15 分)
  6. (Easy) FizzBuzz LeetCode
  7. SpringBoot - MyBatis-Plus使用详解2(设置实体类对应的表名、字段名 )
  8. The Largest Clique UVA - 11324( 强连通分量 + dp最长路)
  9. webstore忽略指定的文件夹显示
  10. 阿里巴巴confont项目的使用
  11. JavaScript 身份证校验正则表达式
  12. jquery 的税收计算器(仅限参考)
  13. 微信小程序自定义页面标题
  14. Python之You-Get库学习
  15. BNUOJ 4140 Video Game Troubles
  16. vuejs中用require引入图片,出现ReferenceError: require is not defined
  17. 2010年9月2号安排~
  18. 【数据结构与算法】详解什么是栈,并用代码手动实现一个栈结构
  19. jr某头条新闻爬虫(超详细)
  20. GitHub桌面版和汉化包,使用详细(GitHub Desktop安装,github软件汉化包详细使用过程)

热门文章

  1. 【Kafka】Kafka InvalidReceiveException: Invalid receive (size = 369296128 larger than 104857600)
  2. 缓存中间件-Memcache命令介绍
  3. 【Flink】Flink时间是如何设计的
  4. 7种方式,教你提升 SpringBoot 项目的吞吐量
  5. leetcode题解14-最长公共前缀
  6. 【2019.08.31】2019银川网络赛(2018银川现场赛)
  7. Redis小记——数据结构
  8. 07_Redis事务
  9. thinkphp5.0解决控制器驼峰命名时提示找不到类名
  10. 翻译文章第六章4-7