Phalcon DI源代码解析
类实现关系
实现关系
- Di实现了DiInterface接口
class Di implements DiInterface{}
DiInterface接口继承自ArrayAccess自定义接口。
interface DiInterface extends \\ArrayAccess{}
所以,在Di中,必须实现如下接口方法:
其中继承自\ArrayAccess预定义接口的:
- offsetExists():判断该下标是否存在。
- offsetGet():获取下标$offset的值。
- offsetSet():设置下标offset的值时调用。
- offsetUnset():取消下标offset。
其中继承自DiInterface接口的:
- set(string! name, definition, boolean shared = false) ->
:注册一个service时,会调用该方法,name表示service名称,definition表示如何定义实现,shared表示是否共享。 - setShared(string! name, definition) ->
:表示注册一个总是共享的服务到services container。 - remove(string! name):从services container中移除一个服务。
- attempt(string! name, definition, boolean shared = false) ->
:向service container中注册之前未注册过的服务,才可以成功。 - get(string! name, parameters = null):解析服务实例。
- getShared(string! name, parameters = null):解析获取一个共享的实例。
- setRaw(string! name,
rawDefinition) -> :使用原始的\Phalcon\Di\Service定义一个服务,即直接给出一个ServiceInterface接口实现类的实例。
/**
* Sets a service using a raw Phalcon\Di\Service definition
*/
public function setRaw(string! name, rawDefinition) ->
{
let this->_services[name] = rawDefinition;
return rawDefinition;
}
- getRaw(string! name):
- getService(string! name) ->
:返回相应name的\Phalcon\Di\Service实例。 - has(string! name) -> boolean:检查容器中是否包含该name的实例。
- wasFreshInstance() -> boolean:检查通过getShared共享的最后一个服务是否生成了一个实例或一个现有存在的实例。
- getServices():从DI中获取实例。
- setDefault(
dependencyInjector):设置默认使用的di容器。 - getDefault() ->
:获取默认使用的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) ->
{
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) -> | 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, rawDefinition) ->
{
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 = 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类解析实例:
小结
注入方式
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()的方式获取。