您的位置:首页 > 编程语言 > PHP开发

yii2 随笔(七)依赖注入——(4)服务定位器

2016-03-28 17:24 561 查看
原文地址:http://ivhong.com/?p=135(ivhong.com
是我的博客主址)

服务定位器定位器是依赖注入的一种解决方式,它包含依赖注入,在解决了依赖注入后,如果服务使用者和服务提供者不是用一个人,那么使用者要了解提供服务的必须参数,这样才能保证依赖的正确性,这就耦合了使用者和提供者,服务定位器就是解耦这部分的,服务提供者在 ServiceLocator 中注册服务(同时注册了依赖),仅仅告诉服务使用者那些服务的名称或者别名,那么对于服务提供者和使用者都是好的,使用者只需要知道提供者提供的什么服务,而不必知道依赖什么,服务提供者也不必为使用者“胡乱使用”服务而导致的bug所困扰。

那么yii2是怎么使用ServiceLocator呢?其实很简单如下

//魔术方法,
public function __get($name){
//得到某个注册的方法
if ($this->has($name)) {
return $this->get($name);
} else {
return parent::__get($name);
}
}
//魔术方法查看某个服务是否存在,源码略
public function __isset($name){}
//__isset()中调用,查看某个服务是否存在,源码略
public function has($id, $checkInstance = false){}
//得到某个服务
public function get($id, $throwException = true)
{
if (isset($this->_components[$id])) {//如果是已经处理的服务,就直接返回
return $this->_components[$id];
}

if (isset($this->_definitions[$id])) {//如定义了该服务
$definition = $this->_definitions[$id];//得到服务的定义
//如果服务是一个闭包,则把闭包注册到已经实例化的服务中,并且返回闭包
if (is_object($definition) && !$definition instanceof Closure) {
return $this->_components[$id] = $definition;
} else {//其他的情况下通过依赖注入生成对象,并且注册为已处理,返回对象
return $this->_components[$id] = Yii::createObject($definition);
}
} elseif ($throwException) {//如果抛出异常,则抛出异常
throw new InvalidConfigException("Unknown component ID: $id");
} else {//其他返回null
return null;
}
}
//注册一个服务
public function set($id, $definition)
{
if ($definition === null) {//如果该服务的定义为null,则删除已经实例化的服务,返回空,用于注销已经实例化的并且保存过的服务的定义
unset($this->_components[$id], $this->_definitions[$id]);
return;
}
//清空已经实例化的服务
unset($this->_components[$id]);
//如果该服务的定义为一个对象,并且是一个可调用的结构
if (is_object($definition) || is_callable($definition, true)) {
// an object, a class name, or a PHP callable
$this->_definitions[$id] = $definition;
} elseif (is_array($definition)) {//如果该服务是一个配置数组
// a configuration array
if (isset($definition['class'])) {//如果有class键值,则直接注册为一个服务的定义
$this->_definitions[$id] = $definition;
} else {//是配置数组,但是没有指定class,则抛出异常
throw new InvalidConfigException("The configuration for the \"$id\" component must contain a \"class\" element.");
}
} else {//什么都不是,抛出异常,非法注册服务
throw new InvalidConfigException("Unexpected configuration type for the \"$id\" component: " . gettype($definition));
}
}
//清空已经实例化过的服务和定义,代码略
public function clear($id){}
//得到已经实例化后的服务,或者得到可用的服务配置
public function getComponents($returnDefinitions = true){}
//注册所有的服务,这里的$components,就是你在config里写的 $config['components']值
public function setComponents($components){}


那么ServiceLocator是从什么时候介入的呢?我们继续开我们的index.php,注意下面那句话

(new yii\web\Application($config))->run();


我们查看Application

class Application extends \yii\base\Application
//继续追踪  \yii\base\Application
abstract class Application extends Module
//继续追踪  Module
class Module extends ServiceLocator


哈,终于找到丫了!!!我们的application 其实就一个服务定位器,我们在配置文件里配置的components,都是application的这个服务定位器注册的服务。这下知道为什么叫做 setComponents这个函数了吧,不明白继续往下看。

yii 用 set[typename] 的函数来确保属性的可写性,在基类 yii\base\Object 的构造函数里使用了 Yii::configure($this, $config);这个会调用 setComponents 函数注册服务。

好啦,前后都联系上了,yii2使用的依赖注入和服务定位器,就说到这里。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: