在Yii.php中:php
<?php class ServiceLocator extends Component { //保存实例化的对象,每一个对象都是单例,且有惟一string类型的ID作区分 private $_components = []; //保存设置的对象或者其定义,用于实例化 private $_definitions = []; //将对象ID做为ServiceLocator的属性,可经过$serviceLocator->{ID}直接获取 public function __get($name) { if ($this->has($name)) { return $this->get($name); } return parent::__get($name); } //检验是否有属性$name public function __isset($name) { if ($this->has($name)) { return true; } return parent::__isset($name); } //检验是否有对象$id public function has($id, $checkInstance = false) { return $checkInstance ? isset($this->_components[$id]) : isset($this->_definitions[$id]); } //获取一个对象$id public function get($id, $throwException = true) { //已经实例化的,直接返回 if (isset($this->_components[$id])) { return $this->_components[$id]; } //有该对象的定义,且定义已是一个对象,设置$_components并直接返回 if (isset($this->_definitions[$id])) { $definition = $this->_definitions[$id]; if (is_object($definition) && !$definition instanceof Closure) { return $this->_components[$id] = $definition; } //有定义但不是现成对象,则交给DI Container去实例化,而且设置$_components return $this->_components[$id] = Yii::createObject($definition); } elseif ($throwException) { throw new InvalidConfigException("Unknown component ID: $id"); } return null; } //设置、存放一个对象 public function set($id, $definition) { unset($this->_components[$id]); if ($definition === null) { unset($this->_definitions[$id]); return; } //若是$definition是对象或者类名或者callable,则注册到$_definitions中 if (is_object($definition) || is_callable($definition, true)) { // an object, a class name, or a PHP callable $this->_definitions[$id] = $definition; } elseif (is_array($definition)) { //若是是带'class'的配置数组,也注册到$_definitions中 // a configuration array if (isset($definition['class'])) { $this->_definitions[$id] = $definition; } 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)); } } //清楚注册的对象 public function clear($id) { unset($this->_definitions[$id], $this->_components[$id]); } }
这里用到了注册树。数组
注册树模式(Registry Pattern)又叫注册模式、注册器模式。注册树模式经过将对象实例注册到一棵全局的对象树上,须要的时候从对象树上采摘的模式设计方法。this
单例模式在整个项目中建立惟一实例的问题;工厂模式封装了对象的建立方式(工厂方法——用一个抽象方法,抽象工厂——用一簇抽象方法),使得没必要总用new关键词去获取对象;建立者模式则是分步骤的建立实例的各个部分;在Yii2中则经过依赖注入容器DI去获取实例...spa
这些方法实际上都是解决一个问题——如何合理的产生一个对象。但对象既然已经产生出来了,怎么方便的调用这些对象呢?咱们在项目内部创建的对象好像散兵游勇同样,不方便统筹管理安排啊。于是注册数模式应运而生。无论你是何种方式产生的对象,都给我“插到”注册树上。我用某个对象的时候,直接从注册树上去取一下就行了,是否是很是方便?注册时模式还为其余模式提供了一种很是好的想法。设计
看看注册树模式的实现:code
class Register { //存放对象的数组 protected static $objects; /** * 存放一个对象 * @param $alias * @param $object */ public static function set($alias,$object) { self::$objects[$alias] = $object; } /** * 获取一个对象 * @param $alias * @return mixed */ public static function get($alias) { return self::$objects[$alias]; } /** * 销毁一个对象 * @param $alias */ public static function _unset($alias) { unset(self::$objects[$alias]); } }
注册树模式很相似服务定位器模式,优势是集中管理,使用方便。缺点是隐藏了对象和对象之间的依赖关系。component
PHP注册树模式主要用于建立对象的时候将咱们的对象与相应的变量进行绑定,从这个角度上说,Yii2的Service Locator和DI Container都用到注册树模式。这两者都在内部维护一个数组(key => value),value为对象或者对象定义,在获取时经过惟一的key来获取,若是是定义再去容器里面实例化一下。对象