ServiceLocator,服务定位类,用于yii2中的依赖注入,通过以ID为索引的方式缓存服务或则组件的实例来定位服务或者组件:

 namespace yii\di;

 use Yii;
 use Closure;
 use yii\base\Component;
 use yii\base\InvalidConfigException;

 /**
  * ServiceLocator implements a [service locator](http://en.wikipedia.org/wiki/Service_locator_pattern).
  *
  * To use ServiceLocator, you first need to register component IDs with the corresponding component
  * definitions with the locator by calling [[set()]] or [[setComponents()]].
  * You can then call [[get()]] to retrieve a component with the specified ID. The locator will automatically
  * instantiate and configure the component according to the definition.
  *
  * For example,
  *
  * ```php
  * $locator = new \yii\di\ServiceLocator;
  * $locator->setComponents([
  *     'db' => [
  *         'class' => 'yii\db\Connection',
  *         'dsn' => 'sqlite:path/to/file.db',
  *     ],
  *     'cache' => [
  *         'class' => 'yii\caching\DbCache',
  *         'db' => 'db',
  *     ],
  * ]);
  *
  * $db = $locator->get('db');  // or $locator->db
  * $cache = $locator->get('cache');  // or $locator->cache
  * ```
  *
  * Because [[\yii\base\Module]] extends from ServiceLocator, modules and the application are all service locators.
  *
  * @property array $components The list of the component definitions or the loaded component instances (ID =>
  * definition or instance).
  *
  * @author Qiang Xue <qiang.xue@gmail.com>
  * @since 2.0
  */
 class ServiceLocator extends Component
 {
     /**
      * @var array shared component instances indexed by their IDs
      * @var array 用于缓存服务、组件等的实例,索引为ID
      */
     private $_components = [];
     /**
      * @var array component definitions indexed by their IDs
      * @var array 用于保存服务和组件的定义,通常为配置数组,可以用来创建具体的实例
      */
     private $_definitions = [];

     /**
      * Getter magic method.
      * 重写了 getter 方法,使得访问服务和组件就跟访问类的属性一样。同时,也保留了原来Component的 getter所具有的功能。
      * This method is overridden to support accessing components like reading properties.
      * @param string $name component or property name
      * @return mixed the named property value
      */
     public function __get($name)
     {
         if ($this->has($name)) {//调用has方法判断是否有某个组件或服务的实例,如果有调用get方法返回该实例
             return $this->get($name);
         } else {//否则把$name当普通属性处理
             return parent::__get($name);
         }
     }

     /**
      * Checks if a property value is null.
      * 重写了 isset 方法,增加了对是否具有某个服务和组件的判断
      * This method overrides the parent implementation by checking if the named component is loaded.
      * @param string $name the property name or the event name
      * @return boolean whether the property value is null
      */
     public function __isset($name)
     {
         if ($this->has($name, true)) {//调用has方法判断是否有某个组件或服务的实例,如果有返回true
             return true;
         } else {//否则判断是否有$name这个属性
             return parent::__isset($name);
         }
     }

     /**
      * Returns a value indicating whether the locator has the specified component definition or has instantiated the component.
      * This method may return different results depending on the value of `$checkInstance`.
      * 当 $checkInstance === false 时,用于判断是否已经定义了某个服务或组件
      * 当 $checkInstance === true 时,用于判断是否已经有了某个服务或组件的实例
      *
      * - If `$checkInstance` is false (default), the method will return a value indicating whether the locator has the specified
      *   component definition.
      * - If `$checkInstance` is true, the method will return a value indicating whether the locator has
      *   instantiated the specified component.
      *
      * @param string $id component ID (e.g. `db`).
      * @param boolean $checkInstance whether the method should check if the component is shared and instantiated.
      * @return boolean whether the locator has the specified component definition or has instantiated the component.
      * @see set()
      */
     public function has($id, $checkInstance = false)
     {
         return $checkInstance ? isset($this->_components[$id]) : isset($this->_definitions[$id]);
     }

     /**
      * Returns the component instance with the specified ID.
      * 根据 $id 获取对应的服务或组件的实例
      *
      * @param string $id component ID (e.g. `db`).
      * @param boolean $throwException whether to throw an exception if `$id` is not registered with the locator before.
      * @return object|null the component of the specified ID. If `$throwException` is false and `$id`
      * is not registered before, null will be returned.
      * @throws InvalidConfigException if `$id` refers to a nonexistent component ID
      * @see has()
      * @see set()
      */
     public function get($id, $throwException = true)
     {
         if (isset($this->_components[$id])) {//如果_components中有该组件或者服务的实例
             return $this->_components[$id];//返回该实例
         }

         if (isset($this->_definitions[$id])) {//如果_definitions中定义了该组件或者服务
             $definition = $this->_definitions[$id];//取得该组件或者服务的值
             if (is_object($definition) && !$definition instanceof Closure) {//如果该值是对象实例且不是Closure(匿名)的实例
                 return $this->_components[$id] = $definition;//则在_components注册该组件或者服务的实例并返回
             } else {
                 return $this->_components[$id] = Yii::createObject($definition);//否则根据定义中的配置参数创建实例并注册返回
             }
         } elseif ($throwException) {//如果允许抛出异常,则抛出异常
             throw new InvalidConfigException("Unknown component ID: $id");
         } else {//否则返回null
             return null;
         }
     }

     /**
      * Registers a component definition with this locator.
      * 用于注册一个组件或服务,其中 $id 用于标识服务或组件。
      * $definition 可以是一个类名,一个配置数组,一个PHP callable(回调函数),或者一个对象
      *
      * For example,
      *
      * ```php
      * // a class name
      * $locator->set('cache', 'yii\caching\FileCache');
      *
      * // a configuration array
      * $locator->set('db', [
      *     'class' => 'yii\db\Connection',
      *     'dsn' => 'mysql:host=127.0.0.1;dbname=demo',
      *     'username' => 'root',
      *     'password' => '',
      *     'charset' => 'utf8',
      * ]);
      *
      * // an anonymous function
      * $locator->set('cache', function ($params) {
      *     return new \yii\caching\FileCache;
      * });
      *
      * // an instance
      * $locator->set('cache', new \yii\caching\FileCache);
      * ```
      *
      * If a component definition with the same ID already exists, it will be overwritten.
      *
      * @param string $id component ID (e.g. `db`).
      * @param mixed $definition the component definition to be registered with this locator.
      * It can be one of the following:
      *
      * - a class name
      * - a configuration array: the array contains name-value pairs that will be used to
      *   initialize the property values of the newly created object when [[get()]] is called.
      *   The `class` element is required and stands for the the class of the object to be created.
      * - a PHP callable: either an anonymous function or an array representing a class method (e.g. `['Foo', 'bar']`).
      *   The callable will be called by [[get()]] to return an object associated with the specified component ID.
      * - an object: When [[get()]] is called, this object will be returned.
      *
      * @throws InvalidConfigException if the definition is an invalid configuration array
      */
     public function set($id, $definition)
     {
         if ($definition === null) {//如果$definition为null,即只传入$id,表示删除
             unset($this->_components[$id], $this->_definitions[$id]);
             return;
         }

         unset($this->_components[$id]);//开始时清空_components中的id

         if (is_object($definition) || is_callable($definition, true)) {//如果传入的$definition是一个类名一个PHP callable(回调函数),或者一个对象
             // an object, a class name, or a PHP callable
             $this->_definitions[$id] = $definition;//直接储存到_definitions中
         } elseif (is_array($definition)) {//如果传入的$definition是一个数组
             // a configuration array
             if (isset($definition['class'])) {//且数组中存在类名
                 $this->_definitions[$id] = $definition;//则将该数组储存到_definitions中
             } else {//否则,抛出异常
                 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));
         }
     }

     /**
      * Removes the component from the locator.
      * 删除一个服务或组件
      * @param string $id the component ID
      */
     public function clear($id)
     {
         unset($this->_definitions[$id], $this->_components[$id]);
     }

     /**
      * Returns the list of the component definitions or the loaded component instances.
      * 用于返回Service Locator的 $_components 数组或 $_definitions 数组,
      * 同时也是 components 属性的getter函数
      * @param boolean $returnDefinitions whether to return component definitions instead of the loaded component instances.
      * @return array the list of the component definitions or the loaded component instances (ID => definition or instance).
      */
     public function getComponents($returnDefinitions = true)
     {
         return $returnDefinitions ? $this->_definitions : $this->_components;
     }

     /**
      * Registers a set of component definitions in this locator.
      * 批量方式注册组件,同时也是 components 属性的setter函数
      * 其实就是以数组的方式传入set方法的参数,遍历后调用set
      *
      * This is the bulk version of [[set()]]. The parameter should be an array
      * whose keys are component IDs and values the corresponding component definitions.
      *
      * For more details on how to specify component IDs and definitions, please refer to [[set()]].
      *
      * If a component definition with the same ID already exists, it will be overwritten.
      *
      * The following is an example for registering two component definitions:
      *
      * ```php
      * [
      *     'db' => [
      *         'class' => 'yii\db\Connection',
      *         'dsn' => 'sqlite:path/to/file.db',
      *     ],
      *     'cache' => [
      *         'class' => 'yii\caching\DbCache',
      *         'db' => 'db',
      *     ],
      * ]
      * ```
      *
      * @param array $components component definitions or instances
      */
     public function setComponents($components)
     {
         foreach ($components as $id => $component) {
             $this->set($id, $component);
         }
     }
 }

Yii源码阅读笔记(三十三)的更多相关文章

  1. Yii源码阅读笔记(十三)

    Model类,集中整个应用的数据和业务逻辑: namespace yii\base; use Yii; use ArrayAccess; use ArrayObject; use ArrayItera ...

  2. Yii源码阅读笔记(一)

    今天开始阅读yii2的源码,想深入了解一下yii框架的工作原理,同时学习一下优秀的编码规范和风格.在此记录一下阅读中的小心得. 每个框架都有一个入口文件,首先从入口文件开始,yii2的入口文件位于we ...

  3. Werkzeug源码阅读笔记(三)

    这次主要讲下werkzeug中的Local. 源码在werkzeug/local.py Thread Local 在Python中,状态是保存在对象中.Thread Local是一种特殊的对象,它是对 ...

  4. Yii源码阅读笔记(三)

    接着上次的继续阅读BaseYii.php vendor/yiisoft/yii2/BaseYii.php—— public static function getRootAlias($alias)// ...

  5. Yii源码阅读笔记(三十五)

    Container,用于动态地创建.注入依赖单元,映射依赖关系等功能,减少了许多代码量,降低代码耦合程度,提高项目的可维护性. namespace yii\di; use ReflectionClas ...

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

    Instance类, 表示依赖注入容器或服务定位器中对某一个对象的引用 namespace yii\di; use Yii; use yii\base\InvalidConfigException; ...

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

    web/Application类的注释,继承base/Application类,针对web应用的一些处理: namespace yii\web; use Yii; use yii\base\Inval ...

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

    Widget类中开始,获取视图对象,获取widget ID,渲染视图,获取路径方法注释: private $_id; /** * Returns the ID of the widget. * 返回插 ...

  9. Yii源码阅读笔记(三十)

    Widget类是所有小部件的基类,开始,结束和渲染小部件内容的方法的注释: namespace yii\base; use Yii; use ReflectionClass; /** * Widget ...

随机推荐

  1. Linux使用手册-时区和时间设置

    1. #vi /etc/sysconfig/clockZONE=”Asia/Shanghai”UTC=false2.#vi /usr/share/zoneinfo/Asia/Shanghai,如果结尾 ...

  2. 音频指纹(Philips)

    参考<A Highly Robust Audio Fingerprinting System> Philips 音频指纹提取流程: 仿真效果: 第一个图为歌曲1的第一个指纹. 第二个图为歌 ...

  3. 调整 ANTD 组件菜单的字体大小。

    调整 ANTD 组件菜单的字体大小:经过多次试验,原有字体太小,只有12px,通过下列CSS 强制加大. 1.分组子菜单(标题) .ant-menu-inline > .ant-menu-sub ...

  4. [mysql]知识补充

    知识概况 视图 函数 存储过程 事务 索引 触发器 [视图] 视图是一个虚拟表,可以实现查询功能,不能进行增删改 本质:根据sql语句获取动态的数据集,并为其命名 1.创建视图 --create vi ...

  5. October 20th Week 43rd Thursday, 2016

    Now, it's clear. OPPO R9s 这一刻 更清晰. I want a new mobile phone, because the one I am using is broken. ...

  6. Linux之tomcat日志管理

    tomcat 的日志输出catalina.out,变大,可使用下面方式解决. cronolog. http://blog.csdn.net/huang_xw/article/details/61942 ...

  7. LeetCode之283. Move Zeroes

    ---------------------------------------------------------------------- 解法一:空间换时间 我使用的办法也是类似于"扫描 ...

  8. flume+kafka+hbase+ELK

    一.架构方案如下图: 二.各个组件的安装方案如下: 1).zookeeper+kafka http://www.cnblogs.com/super-d2/p/4534323.html 2)hbase ...

  9. iOS 线程间共享资源添加排它锁

    #import "ViewController.h" @interface ViewController () @property(nonatomic,strong)NSThrea ...

  10. 移动端使用让图片或者div垂直居中

    ._limgMIiddle{ /* Firefox */ display:-moz-box; -moz-box-pack:center; -moz-box-align:center; /* Safar ...