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 相关文章推荐
第1次亲密接触PHP5(2)
Oct 09 PHP
php adodb连接mssql解决乱码问题
Jun 12 PHP
19个超实用的PHP代码片段
Mar 14 PHP
php生成zip文件类实例
Apr 07 PHP
PHP面向对象程序设计实例分析
Jan 26 PHP
php实现图片缩略图的方法
Mar 29 PHP
PHP中include/require/include_once/require_once使用心得
Aug 28 PHP
老生常谈php 正则中的i,m,s,x,e分别表示什么
Mar 02 PHP
PHP mysqli事务操作常用方法分析
Jul 22 PHP
php反射学习之不用new方法实例化类操作示例
Jun 14 PHP
laravel withCount 统计关联数量的方法
Oct 10 PHP
gearman中worker常驻后台,导致MySQL server has gone away的解决方法
Feb 27 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实现根据设备类型自动跳转相应页面的方法
2014/07/24 PHP
使用GD库生成带阴影文字的图片
2015/03/27 PHP
php 实现进制相互转换
2016/04/07 PHP
thinkPHP多域名情况下使用memcache方式共享session数据的实现方法
2016/07/21 PHP
Yii2中YiiBase自动加载类、引用文件方法分析(autoload)
2016/07/25 PHP
jsvascript图像处理—(计算机视觉应用)图像金字塔
2013/01/15 Javascript
JavaScript限定复选框的选择个数示例代码
2013/08/25 Javascript
JQuery遍历DOM节点的方法
2015/06/11 Javascript
七个不允许错过的jQuery小技巧
2015/12/21 Javascript
学习JavaScript设计模式之单例模式
2016/01/19 Javascript
JavaScript字符串常用的方法
2016/03/10 Javascript
AngularJS优雅的自定义指令
2016/07/01 Javascript
Bootstrap jquery.twbsPagination.js动态页码分页实例代码
2017/02/20 Javascript
vue的.vue文件是怎么run起来的(vue-loader)
2018/12/10 Javascript
移动端如何用下拉刷新的方式实现上拉加载
2018/12/10 Javascript
Vue对象赋值视图不更新问题及解决方法
2019/06/03 Javascript
编写更好的JavaScript条件式和匹配条件的技巧(小结)
2019/06/27 Javascript
如何阻止小程序遮罩层下方图层滚动
2019/09/05 Javascript
Vue的props父传子的示例代码
2020/05/20 Javascript
Python中map和列表推导效率比较实例分析
2015/06/17 Python
快速排序的算法思想及Python版快速排序的实现示例
2016/07/02 Python
利用Python实现颜色色值转换的小工具
2016/10/27 Python
TensorFlow实现Softmax回归模型
2018/03/09 Python
利用python将json数据转换为csv格式的方法
2018/03/22 Python
对python:threading.Thread类的使用方法详解
2019/01/31 Python
django多对多表的创建,级联删除及手动创建第三张表
2019/07/25 Python
Python 处理文件的几种方式
2019/08/23 Python
Python文件操作方法详解
2020/02/09 Python
python递归调用中的坑:打印有值, 返回却None
2020/03/16 Python
用python 绘制茎叶图和复合饼图
2021/02/26 Python
各大浏览器 CSS3 和 HTML5 兼容速查表 图文
2010/04/01 HTML / CSS
英国高街品牌:Miss Selfridge(塞尔弗里奇小姐)
2016/09/21 全球购物
房屋买卖协议书范本
2014/09/27 职场文书
基督教追悼会答谢词
2015/09/29 职场文书
JavaScript正则表达式实现注册信息校验功能
2022/05/30 Java/Android
Oracle数据库事务的开启与结束详解
2022/06/25 Oracle