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源码阅读笔记(三十三)的主要内容,如果未能解决你的问题,请参考以下文章

Yii源码阅读笔记(三十)

Yii源码阅读笔记(三十四)

Yii源码阅读笔记(三十一)

Yii源码阅读笔记(三十二)

yii2源码学习笔记(十三)

Zabbix学习笔记(三十三)