Yii源码阅读笔记(三十三)
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Yii源码阅读笔记(三十三)相关的知识,希望对你有一定的参考价值。
ServiceLocator,服务定位类,用于yii2中的依赖注入,通过以ID为索引的方式缓存服务或则组件的实例来定位服务或者组件:
1 namespace yii\di; 2 3 use Yii; 4 use Closure; 5 use yii\base\Component; 6 use yii\base\InvalidConfigException; 7 8 /** 9 * ServiceLocator implements a [service locator](http://en.wikipedia.org/wiki/Service_locator_pattern). 10 * 11 * To use ServiceLocator, you first need to register component IDs with the corresponding component 12 * definitions with the locator by calling [[set()]] or [[setComponents()]]. 13 * You can then call [[get()]] to retrieve a component with the specified ID. The locator will automatically 14 * instantiate and configure the component according to the definition. 15 * 16 * For example, 17 * 18 * ```php 19 * $locator = new \yii\di\ServiceLocator; 20 * $locator->setComponents([ 21 * ‘db‘ => [ 22 * ‘class‘ => ‘yii\db\Connection‘, 23 * ‘dsn‘ => ‘sqlite:path/to/file.db‘, 24 * ], 25 * ‘cache‘ => [ 26 * ‘class‘ => ‘yii\caching\DbCache‘, 27 * ‘db‘ => ‘db‘, 28 * ], 29 * ]); 30 * 31 * $db = $locator->get(‘db‘); // or $locator->db 32 * $cache = $locator->get(‘cache‘); // or $locator->cache 33 * ``` 34 * 35 * Because [[\yii\base\Module]] extends from ServiceLocator, modules and the application are all service locators. 36 * 37 * @property array $components The list of the component definitions or the loaded component instances (ID => 38 * definition or instance). 39 * 40 * @author Qiang Xue <[email protected]> 41 * @since 2.0 42 */ 43 class ServiceLocator extends Component 44 { 45 /** 46 * @var array shared component instances indexed by their IDs 47 * @var array 用于缓存服务、组件等的实例,索引为ID 48 */ 49 private $_components = []; 50 /** 51 * @var array component definitions indexed by their IDs 52 * @var array 用于保存服务和组件的定义,通常为配置数组,可以用来创建具体的实例 53 */ 54 private $_definitions = []; 55 56 57 /** 58 * Getter magic method. 59 * 重写了 getter 方法,使得访问服务和组件就跟访问类的属性一样。同时,也保留了原来Component的 getter所具有的功能。 60 * This method is overridden to support accessing components like reading properties. 61 * @param string $name component or property name 62 * @return mixed the named property value 63 */ 64 public function __get($name) 65 { 66 if ($this->has($name)) {//调用has方法判断是否有某个组件或服务的实例,如果有调用get方法返回该实例 67 return $this->get($name); 68 } else {//否则把$name当普通属性处理 69 return parent::__get($name); 70 } 71 } 72 73 /** 74 * Checks if a property value is null. 75 * 重写了 isset 方法,增加了对是否具有某个服务和组件的判断 76 * This method overrides the parent implementation by checking if the named component is loaded. 77 * @param string $name the property name or the event name 78 * @return boolean whether the property value is null 79 */ 80 public function __isset($name) 81 { 82 if ($this->has($name, true)) {//调用has方法判断是否有某个组件或服务的实例,如果有返回true 83 return true; 84 } else {//否则判断是否有$name这个属性 85 return parent::__isset($name); 86 } 87 } 88 89 /** 90 * Returns a value indicating whether the locator has the specified component definition or has instantiated the component. 91 * This method may return different results depending on the value of `$checkInstance`. 92 * 当 $checkInstance === false 时,用于判断是否已经定义了某个服务或组件 93 * 当 $checkInstance === true 时,用于判断是否已经有了某个服务或组件的实例 94 * 95 * - If `$checkInstance` is false (default), the method will return a value indicating whether the locator has the specified 96 * component definition. 97 * - If `$checkInstance` is true, the method will return a value indicating whether the locator has 98 * instantiated the specified component. 99 * 100 * @param string $id component ID (e.g. `db`). 101 * @param boolean $checkInstance whether the method should check if the component is shared and instantiated. 102 * @return boolean whether the locator has the specified component definition or has instantiated the component. 103 * @see set() 104 */ 105 public function has($id, $checkInstance = false) 106 { 107 return $checkInstance ? isset($this->_components[$id]) : isset($this->_definitions[$id]); 108 } 109 110 /** 111 * Returns the component instance with the specified ID. 112 * 根据 $id 获取对应的服务或组件的实例 113 * 114 * @param string $id component ID (e.g. `db`). 115 * @param boolean $throwException whether to throw an exception if `$id` is not registered with the locator before. 116 * @return object|null the component of the specified ID. If `$throwException` is false and `$id` 117 * is not registered before, null will be returned. 118 * @throws InvalidConfigException if `$id` refers to a nonexistent component ID 119 * @see has() 120 * @see set() 121 */ 122 public function get($id, $throwException = true) 123 { 124 if (isset($this->_components[$id])) {//如果_components中有该组件或者服务的实例 125 return $this->_components[$id];//返回该实例 126 } 127 128 if (isset($this->_definitions[$id])) {//如果_definitions中定义了该组件或者服务 129 $definition = $this->_definitions[$id];//取得该组件或者服务的值 130 if (is_object($definition) && !$definition instanceof Closure) {//如果该值是对象实例且不是Closure(匿名)的实例 131 return $this->_components[$id] = $definition;//则在_components注册该组件或者服务的实例并返回 132 } else { 133 return $this->_components[$id] = Yii::createObject($definition);//否则根据定义中的配置参数创建实例并注册返回 134 } 135 } elseif ($throwException) {//如果允许抛出异常,则抛出异常 136 throw new InvalidConfigException("Unknown component ID: $id"); 137 } else {//否则返回null 138 return null; 139 } 140 } 141 142 /** 143 * Registers a component definition with this locator. 144 * 用于注册一个组件或服务,其中 $id 用于标识服务或组件。 145 * $definition 可以是一个类名,一个配置数组,一个PHP callable(回调函数),或者一个对象 146 * 147 * For example, 148 * 149 * ```php 150 * // a class name 151 * $locator->set(‘cache‘, ‘yii\caching\FileCache‘); 152 * 153 * // a configuration array 154 * $locator->set(‘db‘, [ 155 * ‘class‘ => ‘yii\db\Connection‘, 156 * ‘dsn‘ => ‘mysql:host=127.0.0.1;dbname=demo‘, 157 * ‘username‘ => ‘root‘, 158 * ‘password‘ => ‘‘, 159 * ‘charset‘ => ‘utf8‘, 160 * ]); 161 * 162 * // an anonymous function 163 * $locator->set(‘cache‘, function ($params) { 164 * return new \yii\caching\FileCache; 165 * }); 166 * 167 * // an instance 168 * $locator->set(‘cache‘, new \yii\caching\FileCache); 169 * ``` 170 * 171 * If a component definition with the same ID already exists, it will be overwritten. 172 * 173 * @param string $id component ID (e.g. `db`). 174 * @param mixed $definition the component definition to be registered with this locator. 175 * It can be one of the following: 176 * 177 * - a class name 178 * - a configuration array: the array contains name-value pairs that will be used to 179 * initialize the property values of the newly created object when [[get()]] is called. 180 * The `class` element is required and stands for the the class of the object to be created. 181 * - a PHP callable: either an anonymous function or an array representing a class method (e.g. `[‘Foo‘, ‘bar‘]`). 182 * The callable will be called by [[get()]] to return an object associated with the specified component ID. 183 * - an object: When [[get()]] is called, this object will be returned. 184 * 185 * @throws InvalidConfigException if the definition is an invalid configuration array 186 */ 187 public function set($id, $definition) 188 { 189 if ($definition === null) {//如果$definition为null,即只传入$id,表示删除 190 unset($this->_components[$id], $this->_definitions[$id]); 191 return; 192 } 193 194 unset($this->_components[$id]);//开始时清空_components中的id 195 196 if (is_object($definition) || is_callable($definition, true)) {//如果传入的$definition是一个类名一个PHP callable(回调函数),或者一个对象 197 // an object, a class name, or a PHP callable 198 $this->_definitions[$id] = $definition;//直接储存到_definitions中 199 } elseif (is_array($definition)) {//如果传入的$definition是一个数组 200 // a configuration array 201 if (isset($definition[‘class‘])) {//且数组中存在类名 202 $this->_definitions[$id] = $definition;//则将该数组储存到_definitions中 203 } else {//否则,抛出异常 204 throw new InvalidConfigException("The configuration for the \"$id\" component must contain a \"class\" element."); 205 } 206 } else {//否则,抛出异常 207 throw new InvalidConfigException("Unexpected configuration type for the \"$id\" component: " . gettype($definition)); 208 } 209 } 210 211 /** 212 * Removes the component from the locator. 213 * 删除一个服务或组件 214 * @param string $id the component ID 215 */ 216 public function clear($id) 217 { 218 unset($this->_definitions[$id], $this->_components[$id]); 219 } 220 221 /** 222 * Returns the list of the component definitions or the loaded component instances. 223 * 用于返回Service Locator的 $_components 数组或 $_definitions 数组, 224 * 同时也是 components 属性的getter函数 225 * @param boolean $returnDefinitions whether to return component definitions instead of the loaded component instances. 226 * @return array the list of the component definitions or the loaded component instances (ID => definition or instance). 227 */ 228 public function getComponents($returnDefinitions = true) 229 { 230 return $returnDefinitions ? $this->_definitions : $this->_components; 231 } 232 233 /** 234 * Registers a set of component definitions in this locator. 235 * 批量方式注册组件,同时也是 components 属性的setter函数 236 * 其实就是以数组的方式传入set方法的参数,遍历后调用set 237 * 238 * This is the bulk version of [[set()]]. The parameter should be an array 239 * whose keys are component IDs and values the corresponding component definitions. 240 * 241 * For more details on how to specify component IDs and definitions, please refer to [[set()]]. 242 * 243 * If a component definition with the same ID already exists, it will be overwritten. 244 * 245 * The following is an example for registering two component definitions: 246 * 247 * ```php 248 * [ 249 * ‘db‘ => [ 250 * ‘class‘ => ‘yii\db\Connection‘, 251 * ‘dsn‘ => ‘sqlite:path/to/file.db‘, 252 * ], 253 * ‘cache‘ => [ 254 * ‘class‘ => ‘yii\caching\DbCache‘, 255 * ‘db‘ => ‘db‘, 256 * ], 257 * ] 258 * ``` 259 * 260 * @param array $components component definitions or instances 261 */ 262 public function setComponents($components) 263 { 264 foreach ($components as $id => $component) { 265 $this->set($id, $component); 266 } 267 } 268 }
以上是关于Yii源码阅读笔记(三十三)的主要内容,如果未能解决你的问题,请参考以下文章