博客 / 詳情

返回

Phalcon2.0.9 源碼解析

Phalcon DI源代碼解析

類實現關係

實現關係

  • Di實現了DiInterface接口

class Di implements DiInterface{}

DiInterface接口繼承自ArrayAccess自定義接口。


interface DiInterface extends \\ArrayAccess{}

PHP ArrayAccess接口

所以,在Di中,必須實現如下接口方法:

其中繼承自\ArrayAccess預定義接口的:

  • offsetExists():判斷該下標是否存在。
  • offsetGet():獲取下標$offset的值。
  • offsetSet():設置下標offset的值時調用。
  • offsetUnset():取消下標offset。

其中繼承自DiInterface接口的:

  • set(string! name, definition, boolean shared = false) -> <ServiceInterface>:註冊一個service時,會調用該方法,name表示service名稱,definition表示如何定義實現,shared表示是否共享。
  • setShared(string! name, definition) -> <ServiceInterface>:表示註冊一個總是共享的服務到services container。
  • remove(string! name):從services container中移除一個服務。
  • attempt(string! name, definition, boolean shared = false) -> <ServiceInterface>:向service container中註冊之前未註冊過的服務,才可以成功。
  • get(string! name, parameters = null):解析服務實例。
  • getShared(string! name, parameters = null):解析獲取一個共享的實例。
  • setRaw(string! name, <ServiceInterface> rawDefinition) -> <ServiceInterface>:使用原始的\Phalcon\Di\Service定義一個服務,即直接給出一個ServiceInterface接口實現類的實例。

/**

* Sets a service using a raw Phalcon\Di\Service definition

*/

public function setRaw(string! name, <ServiceInterface> rawDefinition) -> <ServiceInterface>

{

    let this->_services[name] = rawDefinition;

    return rawDefinition;

}
  • getRaw(string! name):
  • getService(string! name) -> <ServiceInterface>:返回相應name的\Phalcon\Di\Service實例。
  • has(string! name) -> boolean:檢查容器中是否包含該name的實例。
  • wasFreshInstance() -> boolean:檢查通過getShared共享的最後一個服務是否生成了一個實例或一個現有存在的實例。
  • getServices():從DI中獲取實例。
  • setDefault(<DiInterface> dependencyInjector):設置默認使用的di容器。
  • getDefault() -> <DiInterface>:獲取默認使用的di容器
  • reset():將默認的di容器置為null。

di容器類方法解析:

1、構造方法__construct():


/**

* Phalcon\\Di constructor

*/

public function __construct()

{

    var di;

    let di = self::_default;

    if !di {

        let self::_default = this;

    }

}

在構造函數中,會先判斷是否設置了默認使用的di容器,若沒有,則使用當前的di類作為默認容器。

2、set()方法:


/**

* Registers a service in the services container

*/

public function set(string! name, var definition, boolean shared = false) -> <ServiceInterface>

{

    var service;

    let service = new Service(name, definition, shared),

    this->_services[name] = service;

    return service;

}

該方法主要用於向services container中注入一個服務,並且可以設置是否是可共享的,set服務時,其實是實例化了一個\Phalcon\Di\Service類,將該Service實例設置為了di->_services屬性的一項。

3、setShared()方法:

和set()方法不同的是,setShared()方法注入的服務默認是共享的(let service = new Service(name, definition, true))。

4、remove()方法:

在當前di的_services中去掉該服務,且去掉共享的實例屬性。

5、attempt()方法:


/**

* 該方法在注入時,會判斷要注入的服務是否已經存在,若已存在,則不會注入(set和setShared都會覆蓋)

*/

public function attempt(string! name, definition, boolean shared = false) -> <ServiceInterface> | boolean

{

    var service;

    if !isset this->_services[name] {

        let service = new Service(name, definition, shared),

        this->_services[name] = service;

        return service;

    }

    return false;

}

6、setRaw()方法:


/**

* 使用該方法注入時,要求注入的是Phalcon\\Di\\Service接口的一個實例(不會再去實例化Service,而是直接使用該Service接口的實例)

*/

public function setRaw(string! name, <ServiceInterface> rawDefinition) -> <ServiceInterface>

{

    let this->_services[name] = rawDefinition;

    return rawDefinition;

}

7、getRaw()方法:


/**

* 返回一個服務的定義

*/

public function getRaw(string! name) -> var

{

    var service;

    if fetch service, this->_services[name] {

    return service->getDefinition();

    }

    throw new Exception("Service '" . name . "' wasn't found in the dependency injection container");

}

8、getService()方法:

返回某個服務的Service實例。

9、get()方法:

解析並返回某個服務的實例。

/**
* 解析並返回Service實例
*/
public function get(string! name, parameters = null) -> var  
{  
   var service, instance, reflection, eventsManager;  
  
   let eventsManager = <ManagerInterface> this->_eventsManager;  
  
  // 在解析service前會執行di:beforeServiceResolve事件
   if typeof eventsManager == "object" {  
      eventsManager->fire("di:beforeServiceResolve", this, ["name": name, "parameters": parameters]);  
   }  
  // 判斷該服務是否已經註冊
   if fetch service, this->_services[name] {  
      /**  
       * 若已經註冊,則直接調用Service->resolve()方法解析獲取實例
       */  
      let instance = service->resolve(parameters, this);  
   } else {  
      /**  
       * 當未在Service中註冊時,直接調用get某個服務時,di本身也可以作為解析器來使用,去解析獲取實例。
       */  
      if !class_exists(name) {  
         throw new Exception("Service '" . name . "' wasn't found in the dependency injection container");  
      }  
  
      // 判斷參數是否是數組
      if typeof parameters == "array" { 
        // 參數是數組且不為空時,通過反射newInstanceArgs()方法獲取實例
         if count(parameters) {  
            if is_php_version("5.6") {  
               let reflection = new \ReflectionClass(name),  
                  instance = reflection->newInstanceArgs(parameters);  
            } else {  
               let instance = create_instance_params(name, parameters);  
            }  
         } else {  
            // 參數為空時,通過反射的newInstance()方法返回實例
            if is_php_version("5.6") {  
               let reflection = new \ReflectionClass(name),  
                  instance = reflection->newInstance();  
            } else {  
               let instance = create_instance(name);  
            }  
         }  
      } else {  
         if is_php_version("5.6") {  
            let reflection = new \ReflectionClass(name),  
               instance = reflection->newInstance();  
         } else {  
            let instance = create_instance(name);  
         }  
      }  
   }  
  
   /**  
    * 如果解析出來的服務實例本身實現了InjectionAwareInterface接口(即也是一個容器的話),則為該實例設置使用的DI容器
    */  
   if typeof instance == "object" {  
      if instance instanceof InjectionAwareInterface {  
         instance->setDI(this);  
      }  
   }  
  
  // 解析完成後,執行di:afterServiceResolve事件
   if typeof eventsManager == "object" {  
      eventsManager->fire(  
         "di:afterServiceResolve",  
         this,  
         [  
            "name": name,  
            "parameters": parameters,  
            "instance": instance  
         ]  
      );  
   }  
  
   return instance;  
}

10、getShared()方法:

/**
* 獲取Shared服務
*/
public function getShared(string! name, parameters = null)
{
    var instance;
    /**
    * 若存在已經實例化的服務,則直接返回
    */

    if fetch instance, this->_sharedInstances[name] {
        let this->_freshInstance = false;
    } else {
    /**
    * 若不存在已實例化的服務,則解析返回服務
    */
    let instance = this->get(name, parameters);
    
    /**
    * 將實例化的服務放到服務池中
    */
    let this->_sharedInstances[name] = instance,
    this->_freshInstance = true;
    }

    return instance;
}

11、has()方法:

DI容器的標準方法,判斷容器中是否已經注入了該服務。

12、wasFreshInstance()方法:判斷最新得到的實例,是從服務池中直接獲取的還是拿的是已經存在的一個現成的(參照getShared()方法)。

13、getServices()方法:從容器DI中獲取所有已經注入的服務。

14、offsetExists()方法:由於繼承自\ArrayAccess接口,di容器支持數組化訪問,該方法用於判斷某個服務是否存在。

15、offsetSet()方法:di支持通過數組方式設置服務,例如:$this['a'] = 'b';

16、offsetGet()方法:數組方式獲取服務,例如:$a = $this['a'];

17、offsetUnset()方法:代碼中直接return false,目前di不支持unset($this['a'])的方式,移除某個注入的服務。

18、__call()方法:


/**
* 支持通過getA或setA等方法獲取或注入服務。
* @param string method
* @param array arguments
*/

public function __call(string! method, arguments = null) -> var|null

{

    var instance, possibleService, services, definition;

    /**
    * get開頭表示獲取
    */
    if starts_with(method, "get") {
        let services = this->_services,
        possibleService = lcfirst(substr(method, 3));
        if isset services[possibleService] {
            if count(arguments) {
            let instance = this->get(possibleService, arguments);
        } else {
            let instance = this->get(possibleService);
        }

        return instance;
    }

    }

    /**
    * set注入服務
    */
    if starts_with(method, "set") {

        if fetch definition, arguments[0] {

            this->set(lcfirst(substr(method, 3)), definition);

            return null;
        }
    }

    /**

    * 當服務不存在時,返回異常

    */

    throw new Exception("Call to undefined method or service '" . method . "'");

}

19、setDefault()方法:設置默認使用的di容器,具體使用可參考構造函數。

20、getDefault()方法:獲取di容器。

21、reset():將當前默認使用的di容器置null。

/Phalcon/Di/Service類解析實例:

image.png

小結

注入方式

1、setShared():默認注入的是可共享的服務。

2、set():允許定義當前注入的服務是否是可共享的。

3、attempt():允許注入還未注入過的服務,並自定義是否可共享。

4、setRaw():直接注入一個service實例。

5、offsetSet():數組形式注入一個服務,例如:\$this['app'] = $this。

6、__call():魔術方法注入,例如:setA()的方式注入。

獲取方式

1、get():獲取某個服務實例。

2、getShared():獲取可共享的服務。

3、offsetGet():數組方式獲取,例如:\$app = $this['app']。

4、__call():魔術方法獲取,例如:getA()的方式獲取。

user avatar
0 位用戶收藏了這個故事!

發佈 評論

Some HTML is okay.