Laravel学习教程之IOC容器的介绍与用例


Posted in PHP onAugust 15, 2017

前言

Laravel使用IoC(Inversion of Control,控制倒转,这是一个设计模式,可以先查看下百科)容器这个强有力的工具管理类依赖。依赖注入(也是一种设计模式,一般用于实现IoC)是一个不用编写固定代码来处理类之间依赖的方法,相反的,这些依赖是在运行时注入的,这样允许处理依赖时具有更大的灵活性。

理解 Laravel IoC容器是构建强大应用程序所必要的,也有助于Laravel 核心本身。下面话不多说了,来一起看看详细的介绍吧。

基本用例

绑定一个类型到容器

IoC 容器有两种方法来解决依赖关系:通过闭包回调或者自动解析。首先,我们来探究一下闭包回调。首先,需要绑定一个“类型”到容器中:

App::bind('foo', function($app)
{
 return new FooBar;
});

从容器中取得一个类型

$value = App::make('foo');

当执行 App::make 方法,闭包函数被执行并返回结果。

绑定一个”共享“类型到容器

有时,你只想将绑定到容器的类型处理一次,然后接下来从容器中取得的都应该是相同实例:

App::singleton('foo', function()
{
 return new FooBar;
});

绑定一个已经存在的类型实例到容器

你也可以使用instance方法,将一个已经存在的对象接口绑定到容器中:

$foo = new Foo;

App::instance('foo', $foo);

哪里去注册绑定呢

IoC绑定,很像事件句柄或者路由过滤,通常在"bootstrap code(引导代码)"之后完成。换句话说,它们在你的应用程序准备处理请求,也即是在一个路由或者控制器被实际执行之前执行。和其他引导代码一样,start文件通常作为IoC绑定注册一种方法。另外,你可以创建一个app/ioc.php(文件名不一定一样)文件,并在start文件中包含它。

如果你的应用程序有很大量IoC绑定,或者你想根据不同的分类将IoC绑定分割到不同的文件,你可以尝试在服务提供器(见下面)中进行绑定

自动解析

取得一个类

IoC容器足够强大,在许多场景下不需要任何配置就能取得类。例如

class FooBar {

 public function __construct(Baz $baz)
 {
  $this->baz = $baz;
 }

}

$fooBar = App::make('FooBar');

注意:我们虽然没有在容器中注册FooBar类,容器仍然可以取得该类,甚至自动注入Baz依赖!

当某个类型没有绑定到容器,IoC容器将使用 PHP 的反射工具来检查类和读取构造器的类型提示。使用这些信息,容器可以自动构建类实例。

绑定一个接口实现

然而,在某些情况下,一个类可能依赖某个接口实现,而不是一个 “具体的类”。当在这种情况下,App::bind方法必须通知容器注入哪个接口实现:

App::bind('UserRepositoryInterface', 'DbUserRepository');

现在考虑下这个控制器:

class UserController extends BaseController {

 public function __construct(UserRepositoryInterface $users)
 {
  $this->users = $users;
 }

}

由于我们将 UserRepositoryInterface 绑定了具体类,DbUserRepository 在该控制器创建时将会被自动注入到该控制器。

实际用例

Laravel 提供了几个方法使用 IoC 容器增强应用程序可扩展性和可测试性。一个主要的例子是取得控制器。所有控制器都通过 IoC 容器取得,意味着可以在控制器构造方法中对依赖的类型提示,它们将自动被注入。

对控制器的依赖关系做类型提示

class OrderController extends BaseController {

 public function __construct(OrderRepository $orders)
 {
  $this->orders = $orders;
 }

 public function getIndex()
 {
  $all = $this->orders->all();

  return View::make('orders', compact('all'));
 }

}

在这个例子中,OrderRepository 将会自动注入到控制器。意味着当 单元测试 模拟请求时,OrderRepository 将会绑定到容器以及注入到控制器中,允许无痛与数据库层交互。

IoC 使用的其他例子

过滤器, composers, 和 事件句柄也能够从IoC容器中获取到。当注册它们的时候,只需要把它们使用的类名简单给出即可:

Route::filter('foo', 'FooFilter');

View::composer('foo', 'FooComposer');

Event::listen('foo', 'FooHandler');

服务提供器

服务器提供器是将一组相关 IoC 注册到单一路径的有效方法。将它们看做是一种引导组件的方法。在服务器提供器里,你可以注册自定义的验证驱动器,使用 IoC 容器注册应用程序仓库类,甚至是自定义 Artisan 命令。

事实上,大多数核心 Laravel 组件包含服务提供器。应用程序所有注册在服务提供器的均列在  app/config/app.php 配置文件的 providers 数组中。

定义服务提供器

要创建服务提供器,只需继承 Illuminate\Support\ServiceProvider 类并且定义一个 register 方法:

use Illuminate\Support\ServiceProvider;

class FooServiceProvider extends ServiceProvider {

 public function register()
 {
  $this->app->bind('foo', function()
  {
   return new Foo;
  });
 }

}

注意:在 register 方法,应用程序通过 $this->app 属性访问 IoC 容器。一旦你已经创建了提供器并且想将它注册到应用程序中, 只需简单的放入 app 配置文件里 providers 数组中。

运行时注册服务提供器

你也可以使用 App::register 方法在运行时注册服务提供器:

App::register('FooServiceProvider');

容器事件

注册获取事件监听者

容器在每次获取对象时都触发一个事件。你可以通过使用 resolving 方法来监听该事件:

App::resolvingAny(function($object)
{
 //
});

App::resolving('foo', function($foo)
{
 //
});

注意:获取到的对象将会传入回调函数中。

译者:mpandar(马胜盼)

总结

以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作能带来一定的帮助,如果有疑问大家可以留言交流,谢谢大家对三水点靠木的支持。

PHP 相关文章推荐
smtp邮件发送一例
Oct 09 PHP
优化使用mysql存储session的php代码
Jan 10 PHP
Gregarius中文日期格式问题解决办法
Apr 22 PHP
php二分法在IP地址查询中的应用
Aug 12 PHP
PHP 出现乱码和Sessions验证问题的解决方法!
Dec 06 PHP
PHP 解决utf-8和gb2312编码转换问题
Mar 18 PHP
ThinkPHP中__initialize()和类的构造函数__construct()用法分析
Nov 29 PHP
Thinkphp框架开发移动端接口(1)
Aug 18 PHP
PHP正则匹配日期和时间(时间戳转换)的实例代码
Dec 14 PHP
PHP文件管理之实现网盘及压缩包的功能操作
Sep 20 PHP
ThinkPHP5框架实现简单的批量查询功能示例
Jun 07 PHP
PHP7 新增功能
Mar 09 PHP
Laravel 5.4向IoC容器中添加自定义类的方法示例
Aug 15 #PHP
PHP高精确度运算BC函数库实例详解
Aug 15 #PHP
PHP+原生态ajax实现的省市联动功能详解
Aug 15 #PHP
laravel学习笔记之模型事件的几种用法示例
Aug 15 #PHP
PHP实现的回溯算法示例
Aug 15 #PHP
php简单中奖算法(实例)
Aug 15 #PHP
PHP实现的随机红包算法示例
Aug 14 #PHP
You might like
php通过exif_read_data函数获取图片的exif信息
2015/05/21 PHP
PHP生成树的方法
2015/07/28 PHP
thinkPHP5项目中实现QQ第三方登录功能
2017/10/20 PHP
laravel excel 上传文件保存到本地服务器功能
2019/11/14 PHP
Jquery 表单取值赋值的一些基本操作
2009/10/11 Javascript
CSS javascript 结合实现悬浮固定菜单效果
2015/08/23 Javascript
基于javascript实现动态显示当前系统时间
2016/01/28 Javascript
Javarscript中模块(module)、加载(load)与捆绑(bundle)详解
2017/05/28 Javascript
详解使用Vue Router导航钩子与Vuex来实现后退状态保存
2017/09/11 Javascript
Nodejs连接mysql并实现增、删、改、查操作的方法详解
2018/01/04 NodeJs
nodejs结合socket.io实现websocket通信功能的方法
2018/01/12 NodeJs
vue导出html、word和pdf的实现代码
2018/07/31 Javascript
解决mui框架中switch开关通过js控制开或者关状态时小圆点不动的问题
2019/09/03 Javascript
VUE项目初建和常见问题总结
2019/09/12 Javascript
ES6学习笔记之字符串、数组、对象、函数新增知识点实例分析
2020/01/22 Javascript
Node使用Nodemailer发送邮件的方法实现
2020/02/24 Javascript
基于Vue CSR的微前端实现方案实践
2020/05/27 Javascript
[36:14]DOTA2上海特级锦标赛D组小组赛#1 EG VS COL第二局
2016/02/28 DOTA
python遍历文件夹,指定遍历深度与忽略目录的方法
2018/07/11 Python
使用Django2快速开发Web项目的详细步骤
2019/01/06 Python
对python numpy.array插入一行或一列的方法详解
2019/01/29 Python
简单了解django orm中介模型
2019/07/30 Python
numpy求平均值的维度设定的例子
2019/08/24 Python
Django框架models使用group by详解
2020/03/11 Python
使用tensorflow根据输入更改tensor shape
2020/06/23 Python
基于opencv的selenium滑动验证码的实现
2020/07/24 Python
HTML5 WebGL 实现民航客机飞行监控系统
2019/07/25 HTML / CSS
下面这个程序执行后会有什么错误或者效果
2014/11/03 面试题
如何写一个自定义标签
2012/12/28 面试题
电厂厂长岗位职责
2014/01/02 职场文书
大学考试作弊检讨书
2015/05/06 职场文书
2015年个人实习工作总结
2015/05/28 职场文书
雨中的树观后感
2015/06/03 职场文书
七年级上册生物的课件
2019/08/07 职场文书
2019年学校消防安全责任书(2篇)
2019/10/09 职场文书
SQL写法--行行比较
2021/08/23 SQL Server