Yii源码阅读笔记(三十三)
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源码阅读笔记(三十三)的更多相关文章
- Yii源码阅读笔记(十三)
Model类,集中整个应用的数据和业务逻辑: namespace yii\base; use Yii; use ArrayAccess; use ArrayObject; use ArrayItera ...
- Yii源码阅读笔记(一)
今天开始阅读yii2的源码,想深入了解一下yii框架的工作原理,同时学习一下优秀的编码规范和风格.在此记录一下阅读中的小心得. 每个框架都有一个入口文件,首先从入口文件开始,yii2的入口文件位于we ...
- Werkzeug源码阅读笔记(三)
这次主要讲下werkzeug中的Local. 源码在werkzeug/local.py Thread Local 在Python中,状态是保存在对象中.Thread Local是一种特殊的对象,它是对 ...
- Yii源码阅读笔记(三)
接着上次的继续阅读BaseYii.php vendor/yiisoft/yii2/BaseYii.php—— public static function getRootAlias($alias)// ...
- Yii源码阅读笔记(三十五)
Container,用于动态地创建.注入依赖单元,映射依赖关系等功能,减少了许多代码量,降低代码耦合程度,提高项目的可维护性. namespace yii\di; use ReflectionClas ...
- Yii源码阅读笔记(三十四)
Instance类, 表示依赖注入容器或服务定位器中对某一个对象的引用 namespace yii\di; use Yii; use yii\base\InvalidConfigException; ...
- Yii源码阅读笔记(三十二)
web/Application类的注释,继承base/Application类,针对web应用的一些处理: namespace yii\web; use Yii; use yii\base\Inval ...
- Yii源码阅读笔记(三十一)
Widget类中开始,获取视图对象,获取widget ID,渲染视图,获取路径方法注释: private $_id; /** * Returns the ID of the widget. * 返回插 ...
- Yii源码阅读笔记(三十)
Widget类是所有小部件的基类,开始,结束和渲染小部件内容的方法的注释: namespace yii\base; use Yii; use ReflectionClass; /** * Widget ...
随机推荐
- 启动apache和tomcat端口被占用解决办法
1,打开控制台,使用命令 netstat -aon|findstr 8090 找出端口被占用的进程, 2,使用 taskkill -f -pid 4116(进程id)杀掉当前占用端口的进程
- 利用CAReplicatorLayer实现的加载动画
在上一篇中,笔者简要介绍了CAReplicatorLayer,在本篇中,将介绍具体的实用价值. 实用CAReplicatorLayer作为核心技术实现加载动画. 首先,创建一个UIView的子类 @i ...
- iOS 运行时
1.点击每一个cell都要跳转到一个控制器,swich会很麻烦,那么可以用运行时来进行跳转. a. 定义一个数组用来存放控制器的名字 - (NSArray *)controllerArr{ if (_ ...
- linux允许80端口通过
yum重装 http://www.07net01.com/storage_networking/Red_Hat_6_2_64ruheshiyongCentosdeYUMyuangengxinfangf ...
- haproxy 实现多域名证书https
[root@ha02 keys]# openssl genrsa - Generating RSA bit long modulus ....+++ ......................... ...
- 利用Queue队列实现FIFO的算法
#!/usr/bin/env python # -*- coding: utf-8 -*- # learn <<Problem Solving with Algorithms and Da ...
- Linux yum配置文件详解
说明:经过网上抄袭和自己的总结加实验,非常详细,可留作参考. yum的配置一般有两种方式: 一种是直接配置/etc目录下的yum.conf文件, 另外一种是在/etc/yum.repos.d目录下 ...
- sql对于between和时间
在写时间条件 ,比如 把2014/3/1 到2014/3/31这个时间段做为条件 的话,很多人都会写成这样 select date from table where date between '201 ...
- 大部分人都会做错的经典JS闭包面试题
由工作中演变而来的面试题 这是一个我工作当中的遇到的一个问题,似乎很有趣,就当做了一道题去面试,发现几乎没人能全部答对并说出原因,遂拿出来聊一聊吧. 先看题目代码: function fun(n,o) ...
- ADO.NET 读取Excel文件,并作数据源
项目中需要用的功能,贴上代码了. 需要注意的地方:配置Web.config的时候要注意版本问题! //若是在Web.config中配置数据源,如下 <add key="ExcelCon ...