前段时间,有朋友问我yii2的依赖注入是怎么个玩法,好吧,

经常看到却一直不甚理解的概念,这里我再对自己认识的依赖注入深刻的表达下我的理解,依赖注入(DI)以及控制器反转(Ioc)。 依赖注入就是组件通过构造器,方法或者属性字段来获取相应的依赖对象。

举个现实生活中的例子来理解, 比如我要一把菜刀 如何获得
1.可以自己造一把,对应new一个。
2.可以找生产菜刀的工厂去买一把,对应工厂模式。
3.可以打电话 让店家送货上门,对应依赖注入

依赖注入(DI)的概念虽然听起来很深奥,但是如果你用过一些新兴的php框架的话,对于DI一定不陌生,因为它们多多少少都用到了依赖注入来处理类与类之间的依赖关系。

php中传递依赖关系的三种方案

其实要理解DI,首先要明白在php中如何传递依赖关系。 
第一种方案,也是最不可取的方案,就是在A类中直接用new关键词来创建一个B类,如下代码所示:

<?php
class A
{
public function __construct()
{
$b = new B();
} }

为什么这种方案不可取呢?因为这样的话,A与B就耦合在了一起,也就是说A类无法脱离B类工作。 
第二种方案就是在A类的方法中传入需要的B类,如下代码所示:

<?php
class A
{
public function __construct(B $b)
{ } }

这种方法比第一种方案有了改进,A类不必与B类捆绑在一起,只要传入的类满足A类的需求,也可以是C类,也可以是D类等等。 
但是这种方案的弊端在于如果A类依赖的类较多,参数列表会很长,容易发生混乱。 
第三种方案是使用set方法传入,如下代码所示:

<?php
class A
{
public function setB(B $b)
{
$this->b = $b;
} }

这种方案同样存在和第二种方案一样的弊端,当依赖的类增多时,我们需要些很多很多的set方法。

这时我们在想如果有一个专门的类(或者说一个容器)可以帮我们管理这些依赖关系就好了。

一个简单的依赖注入的例子

如下代码来自twittee

<?php
class Container {
private $s=array();
function __set($k, $c) { $this->s[$k]=$c; }
function __get($k) { return $this->s[$k]($this); }
}

有了container类之后我们可以怎样管理A与B之间的依赖关系呢,用代码说话吧:

<?php
class A
{
private $container; public function __construct(Container $container)
{
$this->container = $container;
} public function doSomeThing()
{
//do something which needs class B
$b = $this->container->getB(); //to do
} }

再将B类注入到容器类中:

$c = new Container();
$c->setB(new B());

还可以传入一个匿名函数,这样B类就不会在传入时就立即实例化,而是在真正调用时才完成实例化的工作:

$c = new Container();
$c->setB(function (){
return new B();
});

这里举的只是一个很简单的例子,在实际中,容器类要考虑的有很多,比如延迟加载等等。

再比如我是一个演员,我不可能要求某个导演,我要演某某剧的男一号,相反,导演可以决定让谁来演。而我们的object就是这个演员。

注入的几个途径:
1.construct注入

<?php
class Book {
private $db_conn; public function __construct($db_conn) {
$this->db_conn = $db_conn;
}
}

但是如果依赖过多,那么在构造方法里必然传入多个参数,三个以上就会使代码变的难以阅读。

2.set注入

<?php
$book = new Book();
$book->setdb($db);
$book->setprice($price);
$book->set_author($author);
?>

代码很清晰,但是当我们需要注入第四个依赖时,意味着又要增加一行。

比较好的解决办法是 建立一个class作为所有依赖关系的container,在这个class中可以存放、创建、获取、查找需要的依赖关系

<?php
class Ioc {
protected $db_conn;
public static function make_book() {
$new_book = new Book();
$new_book->set_db(self::$db_conn);
//...
//...
//其他的依赖注入
return $new_book;
}
}

此时,如果获取一个book实例,只需要执行$newone = Ioc::makebook();

以上是container的一个具体实例,最好还是不要把具体的某个依赖注入写成方法,采用registry注册,get获取比较好。

<?php
class Ioc {
/**
* @var 注册的依赖数组
*/ protected static $registry = array(); /**
* 添加一个resolve到registry数组中
* @param string $name 依赖标识
* @param object $resolve 一个匿名函数用来创建实例
* @return void
*/
public static function register($name, Closure $resolve)
{
static::$registry[$name] = $resolve;
} /**
* 返回一个实例
* @param string $name 依赖的标识
* @return mixed
*/
public static function resolve($name)
{
if ( static::registered($name) )
{
$name = static::$registry[$name];
return $name();
}
throw new Exception('Nothing registered with that name, fool.');
}
/**
* 查询某个依赖实例是否存在
* @param string $name id
* @return bool
*/
public static function registered($name)
{
return array_key_exists($name, static::$registry);
}
}

现在就可以通过如下方式来注册和注入一个依赖

<?php
$book = Ioc::registry('book', function(){
$book = new Book;
$book->setdb('...');
$book->setprice('...');
return $book;
}); //注入依赖
$book = Ioc::resolve('book');
?>

再说php依赖注入的更多相关文章

  1. webapi - 使用依赖注入

    本篇将要和大家分享的是webapi中如何使用依赖注入,依赖注入这个东西在接口中常用,实际工作中也用的比较频繁,因此这里分享两种在api中依赖注入的方式Ninject和Unity:由于快过年这段时间打算 ...

  2. ASP.NET Core 中文文档 第四章 MVC(3.8)视图中的依赖注入

    原文:Dependency injection into views 作者:Steve Smith 翻译:姚阿勇(Dr.Yao) 校对:孟帅洋(书缘) ASP.NET Core 支持在视图中使用 依赖 ...

  3. 在WPF中使用依赖注入的方式创建视图

    在WPF中使用依赖注入的方式创建视图 0x00 问题的产生 互联网时代桌面开发真是越来越少了,很多应用都转到了浏览器端和移动智能终端,相应的软件开发上的新技术应用到桌面开发的文章也很少.我之前主要做W ...

  4. MVVM模式解析和在WPF中的实现(六) 用依赖注入的方式配置ViewModel并注册消息

    MVVM模式解析和在WPF中的实现(六) 用依赖注入的方式配置ViewModel并注册消息 系列目录: MVVM模式解析和在WPF中的实现(一)MVVM模式简介 MVVM模式解析和在WPF中的实现(二 ...

  5. .Net Core MVC 网站开发(Ninesky) 2.3、项目架构调整-控制反转和依赖注入的使用

    再次调整项目架构是因为和群友dezhou的一次聊天,我原来的想法是项目尽量做简单点别搞太复杂了,仅使用了DbContext的注入,其他的也没有写接口耦合度很高.和dezhou聊过之后我仔细考虑了一下, ...

  6. ASP.NET Core中如影随形的”依赖注入”[下]: 历数依赖注入的N种玩法

    在对ASP.NET Core管道中关于依赖注入的两个核心对象(ServiceCollection和ServiceProvider)有了足够的认识之后,我们将关注的目光转移到编程层面.在ASP.NET ...

  7. ASP.NET Core中如影随形的”依赖注入”[上]: 从两个不同的ServiceProvider说起

    我们一致在说 ASP.NET Core广泛地使用到了依赖注入,通过前面两个系列的介绍,相信读者朋友已经体会到了这一点.由于前面两章已经涵盖了依赖注入在管道构建过程中以及管道在处理请求过程的应用,但是内 ...

  8. 模拟AngularJS之依赖注入

    一.概述 AngularJS有一经典之处就是依赖注入,对于什么是依赖注入,熟悉spring的同学应该都非常了解了,但,对于前端而言,还是比较新颖的. 依赖注入,简而言之,就是解除硬编码,达到解偶的目的 ...

  9. angular2系列教程(八)In-memory web api、HTTP服务、依赖注入、Observable

    大家好,今天我们要讲是angular2的http功能模块,这个功能模块的代码不在angular2里面,需要我们另外引入: index.html <script src="lib/htt ...

  10. angularjs 依赖注入--自己学着实现

    在用angular依赖注入时,感觉很好用,他的出现是 为了"削减计算机程序的耦合问题" ,我怀着敬畏与好奇的心情,轻轻的走进了angular源码,看看他到底是怎么实现的,我也想写个 ...

随机推荐

  1. jquery.validata.js 插件

    一.Validate插件描述 Validate是基于jQuery的一款轻量级验证插件,内置丰富的验证规则,还有灵活的自定义规则接口,HTML.CSS与JS之间的低耦合能让您自由布局和丰富样式,支持in ...

  2. haproxy+tomcat集群搭建

    web1和web2的部署可参考我之前的文章<Tomcat集群搭建>,这里就省去该过程了. #安装haproxy- .tar.gz cd haproxy-/ make TARGET=linu ...

  3. Django学习(一)---基本配置及创建项目、应用

    安装:在Django官网下载最新版Django然后通过pip安装即可 一.创建项目 进入文件夹,打开cmd窗口,输入django-admin startproject myblog(项目名) 二.创建 ...

  4. visual Studio 2017 扩展开发(一)《向Visual Studio菜单栏新增一个菜单》

    最近有接触到关于visual studio 2017 扩展的开发,特此记录,也是为了督促自己去深入了解其原理. 开始开发Visual Studio 扩展,在这里我安装了visual studio 20 ...

  5. ThinkPhp框架:分页查询和补充框架知识

    上一篇的随笔写的是基本操作,现在可以做一些高级操作,例如有条件的查询数据,有分页的条件查询数据 一.一个条件的查询数据 查询数据自然是先要显示出数据,然后根据条件进行查询数据 (1)显示出表的数据 这 ...

  6. CJOJ 2022 【一本通】简单的背包问题(搜索)

    CJOJ 2022 [一本通]简单的背包问题(搜索) Description 设有一个背包可以放入的物品重量为S,现有n件物品,重量分别是w1,w2,w3,-wn. 问能否从这n件物品中选择若干件放入 ...

  7. java基础04 匿名内部类

    内部类 (1)把类定义在另一个类的内部,该类就被称为内部类. 举例:把类B定义在类A中,类B就被称为内部类. (2)内部类的访问规则 A:可以直接访问外部类的成员,包括私有 B:外部类要想访问内部类成 ...

  8. Mac终端查看sqlite3数据库、表数据等

    背景: 我们在用FMDB处理iOS数据库时,沙盒里保存的数据库格式为.sqlite3. 当我们需要在模拟器上调试或查看数据库内容时,我们可以直接在终端里查看到. 正文: 1.在沙盒路径找到需要查看到文 ...

  9. MySQL后台线程的清理工作

    后台清理工作:脏页刷盘.undo回收 1.page cleaner thread:刷新脏页 2.purge thread:清空undo页.清理“deleted”page 一.innodb_page_c ...

  10. java模拟一个抽奖程序

    今天用一个程序模拟一个从1-32之间,随机抽取7组号码的抽奖程序 * 需要使用Java的图形界面知识 * 窗口  JFrame * 面板  JPanel * 显示文本信息的标签  JLabel * 文 ...