服務定位器定位器是依賴注入的一種解決方式,它包含依賴注入,在解決了依賴注入後,如果服務使用者和服務提供者不是用一個人,那麼使用者要瞭解提供服務的必須參數,這樣才能保證依賴的正確性,這就耦合了使用者和提供者,服務定位器就是解耦這部分的,服務提供者在 ServiceLocator 中註冊服務(同時註冊了依賴),僅僅告訴服務使用者那些服務的名稱或者別名,那麼對於服務提供者和使用者都是好的,使用者只需要知道提供者提供的什麼服務,而不必知道依賴什麼,服務提供者也不必為使用者“胡亂使用”服務而導致的bug所困擾。
那麼yii2是怎麼使用ServiceLocator呢?其實很簡單如下
//魔術方法,public function __get($name){ //得到某個註冊的方法 if ($this->has($name)) { return $this->get($name); } else { return parent::__get($name); }}//魔術方法查看某個服務是否存在,源碼略public function __isset($name){}//__isset()中調用,查看某個服務是否存在,源碼略public function has($id, $checkInstance = false){}//得到某個服務public function get($id, $throwException = true){ if (isset($this->_components[$id])) {//如果是已經處理的服務,就直接返回 return $this->_components[$id]; } if (isset($this->_definitions[$id])) {//如定義了該服務 $definition = $this->_definitions[$id];//得到服務的定義 //如果服務是一個閉包,則把閉包註冊到已經執行個體化的服務中,並且返回閉包 if (is_object($definition) && !$definition instanceof Closure) { return $this->_components[$id] = $definition; } else {//其他的情況下通過依賴注入產生對象,並且註冊為已處理,返回對象 return $this->_components[$id] = Yii::createObject($definition); } } elseif ($throwException) {//如果拋出異常,則拋出異常 throw new InvalidConfigException("Unknown component ID: $id"); } else {//其他返回null return null; }}//註冊一個服務public function set($id, $definition){ if ($definition === null) {//如果該服務的定義為null,則刪除已經執行個體化的服務,返回空,用於登出已經執行個體化的並且儲存過的服務的定義 unset($this->_components[$id], $this->_definitions[$id]); return; } //清空已經執行個體化的服務 unset($this->_components[$id]); //如果該服務的定義為一個對象,並且是一個可調用的結構 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)) {//如果該服務是一個配置數組 // a configuration array if (isset($definition['class'])) {//如果有class索引值,則直接註冊為一個服務的定義 $this->_definitions[$id] = $definition; } else {//是配置數組,但是沒有指定class,則拋出異常 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){}//得到已經執行個體化後的服務,或者得到可用的服務配置public function getComponents($returnDefinitions = true){}//註冊所有的服務,這裡的$components,就是你在config裡寫的 $config['components']值public function setComponents($components){}
那麼ServiceLocator是從什麼時候介入的呢?我們繼續開我們的index.php,注意下面那句話
(new yii\web\Application($config))->run();
我們查看Application
class Application extends \yii\base\Application//繼續追蹤 \yii\base\Applicationabstract class Application extends Module//繼續追蹤 Moduleclass Module extends ServiceLocator
哈,終於找到丫了!!!我們的application 其實就一個服務定位器,我們在設定檔裡配置的components,都是application的這個服務定位器註冊的服務。這下知道為什麼叫做 setComponents這個函數了吧,不明白繼續往下看。
yii 用 set[typename] 的函數來確保屬性的可寫性,在基類 yii\base\Object 的建構函式裡使用了 Yii::configure($this, $config);這個會調用 setComponents 函數註冊服務。
好啦,前後都聯絡上了,yii2使用的依賴注入和服務定位器,就說到這裡。
以上就是yii2 隨筆(七)依賴注入——(4)服務定位器的內容,更多相關內容請關注topic.alibabacloud.com(www.php.cn)!