YII框架的依赖注入容器与服务定位器简述
2016-02-20 13:51
801 查看
依赖注入容器
依赖注入(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();
依赖注入与服务定位器其实都是一个东西的两种不同表现形式而已,在类似的编程环境中,如果是组件类的话,推荐用服务定位器;如果一些非组件类的话可以用依赖注入;
相关文章推荐
- 21.php命名空间
- php.ini 配置详细选项
- PHP 数组操作积累记录
- php不经编译直接输出html
- php7安装
- yii 2 局部关闭 CSRF 拦截
- TP:F7F4FC64
- php解决下单、抽奖并发导致的库存负数的问题
- php开启短标签
- PHP中empty()和isset()的区别
- php 短信验证 容联短信验证
- php正则表达式的基本语法
- 可视化——matplotlib常见api(四)
- Debian安装使用tftp
- RHEL7学习之crontab无法执行ntpdate
- php解析xml,并将xml转换为层级数组
- php分享十八:网页抓取
- ThinkPHP的URL重写时遇到No input file specified的解决方法
- ContentProvider:读取手机通讯录、号码等信息(16)
- JFrame的setBackGround与getContentPane().setBackground区别