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類解析實例:
小結
注入方式
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()的方式獲取。