yii2框架随笔28

今天来看一下ServiceLocator.php

文件目录:di/ServiceLocator.php

<?php
/**
 * @link http://www.yiiframework.com/
 * @copyright Copyright (c) 2008 Yii Software LLC
 * @license http://www.yiiframework.com/license/
 */
namespace yiidi;
use Yii;
use Closure;
use yiibaseComponent;
use yiibaseInvalidConfigException;
/**
 * ServiceLocator implements a [service locator](http://en.wikipedia.org/wiki/Service_locator_pattern).
 * servicelocator实现[服务定位器](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()]].
 * 使用servicelocator,您首先需要注册组件与相应组件的入侵检测系统定义和定位通过调用set()或者[ 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.
 * 然后你可以调用get() [ [ ] ]检索组件与指定的ID。
 * For example,
 *
 * ```php
 * $locator = new yiidiServiceLocator;
 * $locator->setComponents([
 *     'db' => [
 *         'class' => 'yiidbConnection',
 *         'dsn' => 'sqlite:path/to/file.db',
 *     ],
 *     'cache' => [
 *         'class' => 'yiicachingDbCache',
 *         'db' => 'db',
 *     ],
 * ]);
 *
 * ```
 *
 * Because [[yiiaseModule]] 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
{
    /**
     * 存储component的实例,key是component的ID
     * @var array shared component instances indexed by their IDs
     */
    private $_components = [];
    /**
     * 存储component的配置,key是component的ID
     * @var array component definitions indexed by their IDs
     */
    private $_definitions = [];
    /**
     * Getter magic method.
     * 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)
    {
        // 获取component,只要定义中有,就可以拿到
        // 未实例化,get方法会去实例化
        if ($this->has($name)) {
            return $this->get($name);
        } else {
            return parent::__get($name);
        }
    }
    /**
     * Checks if a property value is null.
     * 检查属性值是否为空。
     * 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)
    {
        // 可以看到,如果用isset去判断是否含有某个component,只能判断已经实例化过的component
        if ($this->has($name, true)) {
            return true;
        } else {
            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`。
     *
     * @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)
    {
        // 如果要检查是否有component的实例,就将$checkInstance设置为true
        return $checkInstance ? isset($this->_components[$id]) : isset($this->_definitions[$id]);
    }
    /**
     * Returns the component instance with the specified 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])) {
            // 如果存在就直接返回
            return $this->_components[$id];
        }
        if (isset($this->_definitions[$id])) {
            // 存在component的配置
            $definition = $this->_definitions[$id];
            // 是一个object还不是匿名函数,就代表是一个component的实例
            // 继承自Closure代表是一个匿名函数
            if (is_object($definition) && !$definition instanceof Closure) {
                return $this->_components[$id] = $definition;
            } else {
                // 不是component的实例,就根据配置去创建一个
                return $this->_components[$id] = Yii::createObject($definition);
            }
        } elseif ($throwException) {
            // 都不存在并且允许抛异常的话,就抛异常
            throw new InvalidConfigException("Unknown component ID: $id");
        } else {
            return null;
        }
    }
原文地址:https://www.cnblogs.com/taokai/p/5476341.html