YII框架的依赖注入容器与服务定位器简述
依赖注入容器
依赖注入(Dependency Injection,DI)容器就是一个对象use yii\di\Container
,它知道怎样初始化并配置对象及其依赖的所有对象。
依赖注入和服务定位器都是流行的设计模式,它们使你可以用充分解耦且更利于测试的风格构建软件。
构造方法注入
class Foo
{
public function __construct(Bar $bar)
{
}
}
$container = new Container();
$foo = $container->get('Foo');//get里面是类名注意使用命名空间
// 上面的代码等价于:
$bar = new Bar;
$foo = new Foo($bar);
Setter 和属性注入
use yii\base\Object;
class Foo extends Object
{
public $bar;
private $_qux;
public function getQux()
{
return $this->_qux;
}
public function setQux(Qux $qux)
{
$this->_qux = $qux;
}
}
$container->get('Foo', [], [
'bar' => $container->get('Bar'),
'qux' => $container->get('Qux'),
]);
PHP 回调注入
$container->set('Foo', function () {
return new Foo(new Bar);
});
$foo = $container->get('Foo');
注册依赖关系
可以用 yii\di\Container::set() 注册依赖关系。注册会用到一个依赖关系名称和一个依赖关系的定义。依赖关系名称可以是一个类名,一个接口名或一个别名。依赖关系的定义可以是一个类名,一个配置数组,或者一个 PHP 回调。
$container = new \yii\di\Container;
// 注册一个同类名一样的依赖关系,这个可以省略。
$container->set('yii\db\Connection');
// 注册一个接口
// 当一个类依赖这个接口时,相应的类会被初始化作为依赖对象。
$container->set('yii\mail\MailInterface', 'yii\swiftmailer\Mailer');
// 注册一个别名。
// 你可以使用 $container->get('foo') 创建一个 Connection 实例
$container->set('foo', 'yii\db\Connection');
// 通过配置注册一个类
// 通过 get() 初始化时,配置将会被使用。
$container->set('yii\db\Connection', [
'dsn' => 'mysql:host=127.0.0.1;dbname=demo',
'username' => 'root',
'password' => '',
'charset' => 'utf8',
]);
// 通过类的配置注册一个别名
// 这种情况下,需要通过一个 “class” 元素指定这个类
$container->set('db', [
'class' => 'yii\db\Connection',
'dsn' => 'mysql:host=127.0.0.1;dbname=demo',
'username' => 'root',
'password' => '',
'charset' => 'utf8',
]);
// 注册一个 PHP 回调
// 每次调用 $container->get('db') 时,回调函数都会被执行。
$container->set('db', function ($container, $params, $config) {
return new \yii\db\Connection($config);
});
// 注册一个组件实例
// $container->get('pageCache') 每次被调用时都会返回同一个实例。
$container->set('pageCache', new FileCache);
//注册一个单例的依赖关系
$container->setSingleton('yii\db\Connection', [
'dsn' => 'mysql:host=127.0.0.1;dbname=demo',
'username' => 'root',
'password' => '',
'charset' => 'utf8',
]);
Example
<?php
namespace vendor\driver;
class Car{
private $driver;
//其必须是通过Driver这个接口(类)来实例的,如果通过接口的话在注入的时候就可以达到解耦的目的
public function __construct(Driver $driver){
$this -> driver = $driver;
}
public function run(){
$this -> driver -> run();
}
}
?>
<?php
namespace vendor\driver;
interface Driver{
public function run();
}
?>
<?php
namespace vendor\driver;
class WoManDriver implements Driver{
public function run(){
echo '当心,这是一个女司机';
}
}
?>
<?php
namespace vendor\driver;
class ManDriver implements Driver{
public function run(){
echo '放心,这是一个男司机';
}
}
?>
<?php
namespace app\controllers;
use yii\web\Controller;
use yii\di\Container;
class IndexController extends Controller{
public function actionIndex(){
$container = new Container();
//设置一个别名
$container -> set('car','vendor\driver\Car');
//如果car中的构造方法传入的对象必须是由某个接口而实例的,就还需要使用set方法,否则不需要(如果是类的话注意命名空间的规范既可);
$container -> set('vendor\driver\Driver','vendor\driver\WoManDriver');
//↓↓ 先找到别名,然后实例别名,如果别名不能实例(是个接口),那再通过set注册其依赖关系为接口下面的某个具体的类(究竟是哪个具体的类,可以根据业务逻辑来判断)
$car = $container -> get('car');
$car -> run();
}
}
解决依赖关系
// "db" 是前面定义过的一个别名
$db = $container->get('db');
// 等价于: $engine = new \app\components\SearchEngine($arg1,$arg2,$arg3 );
$engine = $container->get('app\components\SearchEngine', [$arg1,$arg2,$arg3], ['type' => 1]);
# question: 但是这里的 ['type' => 1] ??是什么?无解啊
服务定位器
服务定位器是在应用主体中的一个属性对象,该对象是 yii\di\ServiceLocator 或其子类的一个实例。
最常用的服务定位器是 application(应用)对象,可以通过 \Yii::$app 访问。它所提供的服务被称为 application components(应用组件),比如: request 、 response 、 urlManager 组件。这些组件在 config/web.php中components中配置
除了 application 对象,每个模块对象本身也是一个服务定位器
动态注册
use yii\di\ServiceLocator;
use yii\caching\FileCache;
$locator = new ServiceLocator;
// 通过一个可用于创建该组件的类名,注册 "cache" (缓存)组件。
$locator->set('cache', 'yii\caching\ApcCache');
// 通过一个可用于创建该组件的配置数组,注册 "db" (数据库)组件。
$locator->set('db', [
'class' => 'yii\db\Connection',
'dsn' => 'mysql:host=localhost;dbname=demo',
'username' => 'root',
'password' => '',
]);
// 通过一个能返回该组件的匿名函数,注册 "search" 组件。
$locator->set('search', function () {
return new app\components\SolrService;
});
// 用组件注册 "pageCache" 组件
$locator->set('pageCache', new FileCache);
// 一旦组件被注册成功,你可以任选以下两种方式之一,通过它的 ID 访问它:
$cache = $locator->get('cache');
// 或者
$cache = $locator->cache;
# 你可以通过 yii\di\ServiceLocator::has() 检查某组件 ID 是否被注册。若你用一个无效的 ID 调用yii\di\ServiceLocator::get(),则会抛出一个异常。
$locator = new yii\di\ServiceLocator;
//设置一个别名
//locator中的set只负责设置别名
$locator -> set('car','vendor\driver\Car');
//然后通过全局DI容器设置依赖关系
\Yii::$container -> set('vendor\driver\Driver','vendor\driver\WoManDriver');
//$car = $locator -> get('car');
$car = $locator -> car;
$car -> run();
静态注册
直接配置到web.php中
return
[
// ...
'components' => [
'db' => [
'class' => 'yii\db\Connection',
'dsn' => 'mysql:host=localhost;dbname=demo',
'username' => 'root',
'password' => '',
],
'cache' => 'yii\caching\ApcCache',
'search' => function () {
return new app\components\SolrService;
},
],
];
// 首先在web.php中的components数组加上以下元素
'car' => [
'class' => 'vendor\driver\Car'
]
//然后通过全局DI容器设置依赖关系(非接口情况下可以省略)
\Yii::$container -> set('vendor\driver\Driver','vendor\driver\WoManDriver');
//$car = $locator -> get('car');
$car = \Yii::$app -> car;
$car -> run();
依赖注入与服务定位器其实都是一个东西的两种不同表现形式而已,在类似的编程环境中,如果是组件类的话,推荐用服务定位器;如果一些非组件类的话可以用依赖注入;
YII框架的依赖注入容器与服务定位器简述的更多相关文章
- YII框架的依赖注入容器
依赖注入(Dependency Injection,DI)容器就是一个对象,它知道怎样初始化并配置对象及其依赖的所有对象. 所谓的依赖就是,一个对象,要使用另外一个对象才能完成某些功能.那么这个对象就 ...
- [ASP.NET Core 3框架揭秘] 依赖注入[8]:服务实例的生命周期
生命周期决定了IServiceProvider对象采用怎样的方式提供和释放服务实例.虽然不同版本的依赖注入框架针对服务实例的生命周期管理采用了不同的实现,但总的来说原理还是类似的.在我们提供的依赖注入 ...
- [ASP.NET Core 3框架揭秘] 依赖注入[7]:服务消费
包含服务注册信息的IServiceCollection集合最终被用来创建作为依赖注入容器的IServiceProvider对象.当需要消费某个服务实例的时候,我们只需要指定服务类型调用IService ...
- [ASP.NET Core 3框架揭秘] 依赖注入[6]:服务注册
通过<利用容器提供服务>我们知道作为依赖注入容器的IServiceProvider对象是通过调用IServiceCollection接口的扩展方法BuildServiceProvider创 ...
- [ASP.NET Core 3框架揭秘] 依赖注入[5]: 利用容器提供服务
毫不夸张地说,整个ASP.NET Core框架是建立在依赖注入框架之上的.ASP.NET Core应用在启动时构建管道以及利用该管道处理每个请求过程中使用到的服务对象均来源于依赖注入容器.该依赖注入容 ...
- [ASP.NET Core 3框架揭秘] 依赖注入:控制反转
ASP.NET Core框架建立在一些核心的基础框架之上,这些基础框架包括依赖注入.文件系统.配置选项和诊断日志等.这些框架不仅仅是支撑ASP.NET Core框架的基础,我们在进行应用开发的时候同样 ...
- [ASP.NET Core 3框架揭秘] 依赖注入[10]:与第三方依赖注入框架的适配
.NET Core具有一个承载(Hosting)系统,承载需要在后台长时间运行的服务,一个ASP.NET Core应用仅仅是该系统承载的一种服务而已.承载系统总是采用依赖注入的方式来消费它在服务承载过 ...
- [ASP.NET Core 3框架揭秘] 依赖注入[9]:实现概述
<服务注册>.<服务消费>和<生命周期>主要从实现原理的角度对.NET Core的依赖注入框架进行了介绍,接下来更进一步,看看该框架的总体设计和实现.在过去的多个版 ...
- [ASP.NET Core 3框架揭秘] 依赖注入[4]:一个Mini版的依赖注入框架
在前面的章节中,我们从纯理论的角度对依赖注入进行了深入论述,我们接下来会对.NET Core依赖注入框架进行单独介绍.为了让读者朋友能够更好地理解.NET Core依赖注入框架的设计与实现,我们按照类 ...
随机推荐
- ActiveX控件的基本操作方法以及如何在VS2010下使用控件
在此,小编就介绍下ActiveX控件的基本操作方法以及如何在VS2010下使用控件,我们以一个程序为例, (1) 打开VS2010编译器(右键以管理员身份运行,因为ActiveX需要注册), ...
- apache-commons-net Ftp 进行文件、文件夹的上传下载及日志的输出
用到了apache 的 commons-net-3.0.1.jar 和 log4j-1.2.15.jar 这连个jar包 JAVA 代码如下: package com.bjut.edu.cn.ftp; ...
- 浅谈ERP系统实施后如何完善企业内部控制制度建设
ERP与企业内部控制制度,前者提升企业的管理水平,后者为企业发展保驾护航,两项工作都是企业各项工作的重中之重. ERP是企业资源规划Enterprise Resource Planning的缩写.企业 ...
- Teamwork——Week 4 Daily Scrum Meeting#1 2013.10.23
一.会议议题 1)根据确立的项目题目,进一步明确PM,DEV,TEST的工作. 2)确定团队分工和预估项目时间. 3)完成项目架构NABC模型. 4)确定第一轮开发团队分工 二.会议时间 2013年1 ...
- js数组排序
在JS中,sort方法可用于数组的排序:先来看一个例子: var arr = [1, 2, 3, 5, 7, 78, 8, 89]; arr.sort(); console.log(arr); // ...
- 如何维护SSH安全
遇到两次,一次是公司服务器搭建好后,有人尝试ssh暴力破解,auth.log不停出现错误提示 还有买的米国vps,很荣幸地遭到来自波兰的ssh破解尝试 不得不重视ssh的安全 方法: 修改sshd_c ...
- PostgreSQL中的引号和null
今天工作时写了一个sql,但是PostgreSQL总是提示有语法错误,简单的做个记录: 问题1.'' 和“”单引号和双引号 举个例子: #.select id, delivery_d ...
- [百度空间] [原]MFC杂乱笔记
1. 创建动态菜单 假如ID是动态分配的,那么重载virtual BOOLOnCmdMsg(UINT,int,void*,AFX_CMDHANDLERINFO*); 据MSDN不详细解释,当第二个参数 ...
- MySQL 5.7 虚拟列 (virtual columns)
参考资料: Generated Columns in MySQL 5.7.5 MySQL 5.7新特性之Generated Column(函数索引) MySQL 5.7原生JSON格式支持 Gener ...
- KMP--路过
HDU 1358:弄清楚了NEXT,就好解决,还有不要再循环中用strlen;会超 ----------------------我是凑字数的------------------还是不会KMP----- ...