前段时间,有朋友问我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. usaco training 4.1.3 fence6 题解

    Fence Loops题解 The fences that surround Farmer Brown's collection of pastures have gotten out of cont ...

  2. IE过滤器

    1.  _ 下划线属性过滤器  语法:_选择符{属性:属性值}   2. *通配符属性过滤器 语法:*选择符{属性:属性值}   3.  \9: IE版本识别:其他浏览器都不识别 语法:选择符{属性: ...

  3. .net core建站踩坑记录

    系统:win10 VS版本:2017 .NET Core 版本: 1.1 零.读取配置文件 参考:http://www.tuicool.com/articles/QfYVBvi 此版本无需添加其他组件 ...

  4. centos7安装nodejs

    方法一.https://github.com/nodesource/distributions#rpminstall 按照上面地址中的教程安装完后,使用node -v命令报错: -bash: /usr ...

  5. C++学习(二) 入门篇

      程序清单2. carrots.cpp //carrots.cpp - - food processing program //uses and displays a variable #inclu ...

  6. Swift语法初见

    Swift语法初见 http://c.biancheng.net/cpp/html/2424.html 类型的声明: let implicitInteger = 70 let implicitDoub ...

  7. 在Linux下安装Oracle12c

    其实,对于oracle数据库和oracle实例的安装,借用图形化安装还是比较容易的,只是有个别地方需要特别注意外,其余的默认安装即可: 1.安装前的准备: 启动SSH工具: 先启动倒数第三个(想用图像 ...

  8. Android - Daydream 互动屏保

    Android Daydream 互动屏保 API19 API23 Create:2016-03-01 继承DreamService来实现一个自定义屏保 Dreams是当充电的设备空闲,或者插入底座时 ...

  9. DNS,TCP,IP,HTTP,socket,Servlet概念整理

    DNS,TCP,IP,HTTP,socket,Servlet概念整理   常见的协议虽然很容易理解,但是看了之后过一段时间不看还是容易忘,笔记如下,比较零碎,勉强供各位复习.如有错误欢迎指正.   D ...

  10. 【原创】Easyui tree filter 过滤本地数据无效的原因

    Easyui tree filter 过滤本地数据无效的解决方式    正确使用方式 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 ...