PHP註冊樹模式主要用於創建對象的時候將我們的對象與相應的變數進行綁定,從這個角度上說,Yii2的Service Locator和DI Container都用到註冊樹模式。這二者都在內部維護一個數組(key => value),value為對象或者對象定義,在獲取時通過唯一的key來獲取,如果是定義... ...
應用舉例
在Yii.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)又叫註冊模式、註冊器模式。註冊樹模式通過將對象實例註冊到一棵全局的對象樹上,需要的時候從對象樹上採摘的模式設計方法。
為什麼要採用註冊樹模式?
單例模式在整個項目中創建唯一實例的問題;工廠模式封裝了對象的創建方式(工廠方法——用一個抽象方法,抽象工廠——用一簇抽象方法),使得不必總用new關鍵詞去獲取對象;創建者模式則是分步驟的創建實例的各個部分;在Yii2中則通過依賴註入容器DI去獲取實例...
這些方法實際上都是解決一個問題——如何合理的產生一個對象。但對象既然已經產生出來了,怎麼方便的調用這些對象呢?我們在項目內部建立的對象好像散兵游勇一樣,不方便統籌管理安排啊。因而註冊數模式應運而生。不管你是何種方式產生的對象,都給我“插到”註冊樹上。我用某個對象的時候,直接從註冊樹上去取一下就好了,是不是非常方便?註冊時模式還為其他模式提供了一種非常好的想法。
代碼實現
看看註冊樹模式的實現:
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]);
}
}
註冊樹模式很類似服務定位器模式,優點是集中管理,使用方便。缺點是隱藏了對象和對象之間的依賴關係。
Yii2的註冊樹模式
PHP註冊樹模式主要用於創建對象的時候將我們的對象與相應的變數進行綁定,從這個角度上說,Yii2的Service Locator和DI Container都用到註冊樹模式。這二者都在內部維護一個數組(key => value),value為對象或者對象定義,在獲取時通過唯一的key來獲取,如果是定義再去容器裡面實例化一下。