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()的方式获取。

阅读 514

推荐阅读