文档章节

laravel依赖注入和控制反转

eatnothing
 eatnothing
发布于 2016/05/15 19:32
字数 2159
阅读 580
收藏 6

依赖注入与控制反转

依赖注入 当我第一次接触这个词的时候,我是有些丈二和尚摸不着头脑的,至今我也是感到比较困惑的,所以今天我们来探索一下Laravel中的依赖注入(dependency injection), 来好好的理解它。 控制反转 第一印象是好深奥的名词。。。看上去好像是说反向控制?不懂?那就理顺之!

起点

什么是依赖

没有你我就活不下去,那么,你就是我的依赖。 说白了就是:

不是我自身的,却是我需要的,都是我所依赖的。一切需要外部提供的,都是需要进行依赖注入的。

我们用代码来描述一下:

class Boy {
  protected $girl;

  public function __construct(Girl $girl) {
    $this->girl = $girl;
  }
}

class Girl {
  ...
}

$boy = new Boy();  // Error; Boy must have girlfriend!

// so 必须要给他一个女朋友才行 
$girl = new Girl();

$boy = new Boy($girl); // Right! So Happy!

从上述代码我们可以看到Boy强依赖Girl必须在构造时注入Girl的实例才行。

那么为什么要有依赖注入这个概念,依赖注入到底解决了什么问题?

我们将上述代码修正一下我们初学时都写过的代码:

class Boy {
  protected $girl;

  public function __construct() {
    $this->girl = new Girl();
  }
}

这种方式与前面的方式有什么不同呢?

我们会发现Boy的女朋友被我们硬编码到Boy的身体里去了。。。 每次Boy重生自己想换个类型的女朋友都要把自己扒光才行。。。 (⊙o⊙)…

某天Boy特别喜欢一个LoliGirl ,非常想让她做自己的女朋友。。。怎么办? 重生自己。。。扒开自己。。。把Girl扔了。。。把 LoliGirl塞进去。。。

class LoliGirl {

}

class Boy {
  protected $girl; 

  public function __construct() {
      //  $this->girl = new Girl();  // sorry...
      $this->girl = new LoliGirl();
  }
}

某天 Boy迷恋上了御姐.... (⊙o⊙)… Boy 好烦。。。

是不是感觉不太好?每次遇到真心相待的人却要这么的折磨自己。。。

Boy说,我要变的强大一点。我不想被改来改去的!

好吧,我们让Boy强大一点:

interface Girl {
  // Boy need knows that I have some abilities.
}

class LoliGril implement Girl {
  // I will implement Girl's abilities.
}

class Vixen implement Girl {
  // Vixen definitely is a girl, do not doubt it.
}

class Boy {
  protected $girl;

  public function __construct(Girl $girl) {
    $this->girl = $girl;
  }
}

$loliGirl = new LoliGirl();
$vixen = new Vixen();

$boy = new Boy($loliGirl);
$boy = new Boy($vixen);

Boy很高兴,终于可以不用扒开自己就可以体验不同的人生了。。。So Happy!

小结

因为大多数应用程序都是由两个或者更多的类通过彼此合作来实现业务逻辑,这使得每个对象都需要获取与其合作的对象(也就是它所依赖的对象)的引用。如果这个获取过程要靠自身实现,那么将导致代码高度耦合并且难以维护和调试。

所以才有了依赖注入的概念,依赖注入解决了以下问题:

  • 依赖之间的解耦
  • 单元测试,方便Mock

=。= 前面的依赖注入居然需要我们手动的去注入依赖,做为程序员的我们怎么可以容忍这种低效的注入方式,好吧,我们先来了解一下IOC的概念.

控制反转 (Inversion Of Control, IOC)

控制反转 是面向对象编程中的一种设计原则,可以用来减低计算机代码之间的耦合度。其中最常见的方式叫做依赖注入(Dependency Injection, DI), 还有一种叫"依赖查找"(Dependency Lookup)。通过控制反转,对象在被创建的时候,由一个调控系统内所有对象的外界实体,将其所依赖的对象的引用传递给它。也可以说,依赖被注入到对象中。

也就是说,我们需要一个调控系统,这个调控系统中我们存放一些对象的实体,或者对象的描述,在对象创建的时候将对象所依赖的对象的引用传递过去。 在Laravel中Service Container就是这个高效的调控系统,它是laravel的核心。 下面我们看一下laravel是如何实现自动依赖注入的。

laravel中的依赖注入

现在我们看文档给的例子应该就不难理解了:

<?php

namespace App\Jobs;

use App\User;
use Illuminate\Contracts\Mail\Mailer;
use Illuminate\Contracts\Bus\SelfHandling;

class PurchasePodcast implements SelfHandling
{
    /**
     * The mailer implementation.
     */
    protected $mailer;

    /**
     * Create a new instance.
     *
     * @param  Mailer  $mailer
     * @return void
     */
    public function __construct(Mailer $mailer)
    {
        $this->mailer = $mailer;
    }

    /**
     * Purchase a podcast.
     *
     * @return void
     */
    public function handle()
    {
        //
    }
}

In this example, the PurchasePodcast job needs to send e-mails when a podcast is purchased. So, we willinject a service that is able to send e-mails. Since the service is injected, we are able to easily swap it out with another implementation. We are also able to easily "mock", or create a dummy implementation of the mailer when testing our application.

说到laravel中的依赖注入,我们不得不了解laravel的Service Container

服务容器 (Service Container)

The Laravel service container is a powerful tool for managing class dependencies and performing dependency injection. Dependency injection is a fancy phrase that essentially means this: class dependencies are "injected" into the class via the constructor or, in some cases, "setter" methods.

从介绍不难看出服务容器就是控制反转的容器,它就是前文说到的调度系统。实现依赖注入的方式可以是在构造函数中或者setter方法中。

如果我们仔细研究了Service Container我们就会发现laravel的服务容器中只存储了对象的描述,而并不需要知道如何具体的去构造一个对象,因为它会根据php的反射服务去自动解析具体化一个对象。

反射

在计算机科学中,反射是指计算机在运行时(Run time)可以访问、检测和修改它本身状态或行为的一种能力。用来比喻说,那种程序能够“观察”并且修改自己的行为。

支持反射的语言提供了一些在低级语言中难以实现的运行时特性。这些特性包括

  • 作为一个第一类对象发现并修改源代码的结构(如代码块、类、方法、协议等)。
  • 将跟class或function匹配的转换成class或function的调用或引用。
  • 在运行时像对待源代码语句一样计算字符串。
  • 创建一个新的语言字节码解释器来给编程结构一个新的意义或用途。

PHP实现的反射可以在官网文档中进行查看: 反射API

Example
$reflector = new ReflectionClass('App\User');

if ($reflector->isInstantiable()) {
  $user = $refector->newInstance(); //in other case you can send any arguments
}

laravel的服务容器的build方法中需要通过反射服务来解析依赖关系,比如说construct函数中需要传递的依赖参数有哪些? 它就需要用到如下方法:

   $constructor = $reflector->getConstructor();

   // If there are no constructors, that means there are no dependencies then
   // we can just resolve the instances of the objects right away, without
   // resolving any other types or dependencies out of these containers.
   if (is_null($constructor)) {
       array_pop($this->buildStack);

       return new $concrete;
   }

   $dependencies = $constructor->getParameters();

现在我们应该对laravel如何实现依赖的自动注入有点想法了吧?来整理一下疑问:

  • 如何实现依赖的自动注入? (控制反转,利用反射)
  • 依赖注入需要哪些东东? (整理依赖关系[ construct | setter ],还要解析依赖传递引用)
  • 怎么解析依赖?

你可能会问为什么要问怎么解析依赖?解析依赖肯定是要用到反射的啦,反射,你知道类名不就可以直接解析了吗?

其实。。。不是这样的。。。(@ο@)

很多时候我们为了提高代码的扩展性和维护性,在编写类时依赖的是接口或抽象类,而并不是一个具体的实现类。明白了吗?依赖解析的时候如果只解析到接口或抽象类,然后利用反射,那么这个依赖肯定是错误的。

那么我们就需要在调度系统中注入相关依赖的映射关系,然后在需要的时候正确的解析关系。 比如说, 喂, 我需要一个 A, 你别给我 B 啊。

$container->bind('a', function () {
  return new B();  // just this for you
});

$a = $container->make('a');

总结

  • 依赖注入是控制反转的一种实现,实现代码解耦,便于单元测试。因为它并不需要了解自身所依赖的类,而只需要知道所依赖的类实现了自身所需要的方法就可以了。你需要我,你却不认识我/(ㄒoㄒ)/~~
  • 控制反转提供一种调控系统,实现依赖解析的自动注入,一般配合容器提供依赖对象实例的引用。

本文转载自:https://phphub.org/topics/2104

下一篇: jQuery学习
eatnothing
粉丝 39
博文 128
码字总数 68736
作品 0
昌平
程序员
私信 提问
关于Laravel的核心分析

最近一段时间在研究laravel的底层源码,既然这样那得从开头说起,于是去了laravel学院看看别人写的关于laravel的核心分析,链接如下: Laravel 服务容器实例教程 —— 深入理解控制反转(IoC...

全栈coder
2017/03/10
0
0
laravel 服务容器实现原理

前言 通过实现laravel 框架功能,以便深入理解laravel框架的先进思想。 什么是服务容器 服务容器是用来管理类依赖与运行依赖注入的工具。Laravel框架中就是使用服务容器来实现 控制反转 和 ...

技术小牛人
2017/11/14
0
0
From Apprentice To Artisan 翻译 03

上一篇 The IoC Container 控制反转容器 Basic Binding 基础绑定 Now that we've learned about dependency injection, let's explore inversion of control containers.IoC containers make......

zgldh
2014/09/08
6.2K
0
控制反转( IoC)和依赖注入(DI)

控制反转( IoC)和依赖注入(DI) tags: 容器 依赖注入 IOC DI 控制反转 引言:如果你看过一些框架的源码或者手册,像是laravel或者tp5之类的,应该会提到容器,依赖注入,控制反转等词汇。...

相思叶
2018/03/29
0
0
laravel创建服务

laravel关于这块的教程很多, 所谓控制反转,就是把该由主类全部完成的事情改由子类去完成,这种设计思路就叫控制反转 实现控制反转有多种方式,工厂模式便是一种比较常见的模式,什么是工厂...

tree2013
2016/03/25
114
0

没有更多内容

加载失败,请刷新页面

加载更多

秒杀系统思路

业务分析 技术挑战 请求响应要快:无论成功失败,需要尽快返回给用户 架构设计   前端:静态化   站点层:限制请求数   服务层:乐观锁写缓存   数据库CAP:读写高可用,一致性,扩容...

雷开你的门
21分钟前
10
0
最全的教育行业大数据解决方案,个个针对痛点

大数据的悄然兴起也带动了教育行业的革新,移动教育、云课堂等的出现,使得教育行业再次成为了可以中长期保持高景气的行业。然而,初涉数据领域的教育行业同时也面临着相当大的难题,还需要更...

朕想上头条
25分钟前
7
0
预约模块设计分析

1.预约功能描述: 预约是小程序中常见的一种商品管理系统,商家可根据商品或服务的特性,灵活设置预约细节,为用户提供线上预约服务,如场地预约,商品预定等,实现高效经营。 预约场景: ...

鱼煎
29分钟前
5
0
阿里云日志服务构建网站实时分析大盘实战

场景分析 挖掘数据价值是当前企业级网站共同面临的问题。买买网是一个电商平台网站,每天拥有大量的用户访问和购买记录。为了引导用户直接消费,提升购买率和转化率,不同的用户类别需要推荐...

阿里云官方博客
30分钟前
3
0
TL665xF-EasyEVM开发板硬件处理器、NAND FLASH、RAM

广州创龙结合TI KeyStone系列多核架构TMS320C665x及Xilinx Artix-7系列FPGA设计的TL665xF-EasyEVM开发板是一款DSP+FPGA高速大数据采集处理平台,其底板采用沉金无铅工艺的6层板设计,适用于高...

Tronlong创龙
33分钟前
11
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部