#phalapi-進階篇2(DI依賴注入和單例模式)#

##前言##
***先在這里感謝phalapi框架創始人@dogstar,為我們提供了這樣一個優秀的開源框架.***
離上一次更新過去了快兩周,在其中編寫了一個關于DB分表分庫解決大數據量的拓展,有興趣的童鞋可以了解了解.廢話不多說,本小節在于解釋一下在PhalApi框架中兩個比較好的思想,單例模式和依賴注入.
附上:
喵了個咪的博客:[w-blog.cn](w-blog.cn)
官網地址:[http://www.phalapi.net/](http://www.phalapi.net/ "PhalApi官網")
開源中國Git地址:[http://git.oschina.net/dogstar/PhalApi/tree/release](http://git.oschina.net/dogstar/PhalApi/tree/release "開源中國Git地址")
##1. 單例模式##
單例模式對于長期進行過面向對象編程的童鞋應該不算陌生,對學習php的童鞋也應該有聽過,這里簡單的聊一聊單例模式它到底是一個怎么樣的東東,解決了怎么樣的問題,并且在PhalApi中它是如何實現的.
單例單例,所謂單例也就是保證一個類僅有一個實例,并提供一個訪問它的全局訪問點,這就是單例,不難看出他的好處:資源利用少,因為只有一個,大家都是知道要使用一個類必須要實例他,也就是new,在每次new一個對象的時候都會在內存中生成一塊區域來存放這個實例,如果在程序一次運行中使用了很多的new實例化了同一個對象,那就比較消耗資源了,但是如果是通用一個使用全局變量**global**程序又會顯得不那么優雅而且會很亂,在這種情況下,單例模式就產生了.
單例模式是一個很好的解決方案,既可以全局通用,又不必擔心占用過多的資源,且非常優雅。我們來一起看看在PhalApi中是如何實現單例模式的:
//大家看到我們常用的DI方法內部實現的是PhalApi_DI中的靜態方法one方法
function DI() {
return PhalApi_DI::one();
}
然后我們看向one方法內部
每當請求過來時先驗證靜態變量instance是否已被類初始化賦值,若無,則會在內部去實例化**PhalApi_DI**類,然后賦值給**$instance**并返回,若有,則當下次請求過來時,直接返回已實例化的對象。簡言之,PhalApi框架所有的地方使用的DI方法,其實都是返回同一個對象實例,在內存中只存在一塊區域,代碼如下:
public static function one(){
if(self::$instance == NULL){
self::$instance = new PhalApi_DI();
self::$instance->onConstruct();
}
return self::$instance;
}
##2. 依賴注入##
依賴注入又稱之為**"控制反轉"**,如果是熟悉javaweb開發的**spring**框架應該有比較深的感觸,在這里也不往深的講,就簡單講解一下PhalApi中DI依賴注入的實現,以便讓大家了解這種設計模式實現原理以及自此基礎上實現的惰性加載機制.
###2.1 DI依賴注入實現###
大家在PhalApi中常用的**DI()**方法,也就是采用我們上面所謂的單例模式,我們每次使用DI()就是在使用**PhalApi_DI**類,其實我們依賴注入的關鍵也就是在PhalApi_DI之中
先來講一下他的一個實現方式再來講具體實現,這里舉個例子:
//配置
DI()->config = new PhalApi_Config_File(API_ROOT . '/Config');
其實在內部有一個數組,它把**config**作為了key,把**new PhalApi_Config_File(API_ROOT . '/Config')**作為了value,然后保存了起來。當我們下一次使用**DI->config->get()**的時候,它就會根據key值config拿出開始new好的類,所以可以說**config操作是依賴于DI()**,而且在使用DI()->config的時候永遠都是在使用同一個實例,減少資源的消耗.
有的童鞋就好奇了為什么DI()->config會存到數組里而在需要的時候會拿出來?感興趣的童鞋可以百度一下魔法方法**__set和__get**
/**大家可以看到這是PhalApi_DI中的魔法方法__set
* 也就是當使用DI()->config = new PhalApi_Config_File(API_ROOT . '/Config');的時候
* 獲得的name值就是config,獲得的value也就是new PhalApi_Config_File(API_ROOT . '/Config');
*/get同理,在內部實現都是調用了內部get和set方法
public function __set($name, $value){
$this->set($name, $value);
}
public function __get($name){
return $this->get($name, NULL);
}
看完之后大家是不是覺得很簡單啊,大家以后也可以在設計自己的類的時候采用這種靈活的魔法方法實現.
###2.2 惰性加載###
在PhalApi中的DI()方法也提供惰性加載,惰性加載如字意也就是當類沒有被使用到的時候不會被加載,這樣的操作也是為了避免浪費不必要的資源,當我們不使用的時候永遠不會去實例化,只有當你使用到的時候才會去實例化。接下來,我們來看看是如何實現的.
//當我們執行以下語句的時候,在依賴注入的時候存的是value值是字符串的test
DI()->test = 'test';
//使用DI()->test->test();的時候會使用到PhalApi中的get方法,在get方法中有一段代碼
$this->data[$key] = $this->initService($this->data[$key]);
//在initService方法內部驗證了value是字符串就實例化了再返回
if($config instanceOf Closure){
$rs = $config();
}elseif(is_string($config) && class_exists($config)){
$rs = new $config();
if(is_callable(array($rs, 'onInitialize'))){
call_user_func(array($rs, 'onInitialize'));
}
}else{
$rs = $config;
}
##3. 總結##
在本節中簡單的講解了關于單例模式,依賴注入以及惰性加載,這幾種設計模式都是常用的,能夠減少資源利用率,希望大家看了這篇介紹能夠親自地去體驗一下PhalApi中的這幾種模式。在下一小節就講解如何構建自己的攔截器,希望大家能夠繼續關注!
注:筆者能力有限,有說的不對的地方,希望大家能夠指出,也希望多多交流!
**官網QQ交流群:421032344 歡迎大家的加入!**
####[上一章](/wikis/%5b7.7%5d-phalapi-%e8%bf%9b%e9%98%b6%e7%af%871(%e4%b8%89%e5%b1%82%e7%bb%93%e6%9e%84Api%2cDomain%2c%e5%92%8cModel).html) [文檔首頁](/wikis/) [下一章](/wikis/%5b7.9%5d-phalapi-%e8%bf%9b%e9%98%b6%e7%af%873(%e8%87%aa%e5%8a%a8%e5%8a%a0%e8%bd%bd%e5%92%8c%e6%8b%a6%e6%88%aa%e5%99%a8).html)
- 空白目錄
- [7.1]-phalapi-入門篇1(簡單介紹以及環境搭建)
- [7.2]-phalapi-入門篇2(把它玩起來)
- [7.3]-phalapi-入門篇3(請求和返回)
- [7.4]-phalapi-入門篇4(國際化高可用和自動生成文檔)
- [7.5]-phalapi-入門篇5(數據庫操作和Model層)
- [7.6]-phalapi-入門篇6(小技巧和淺談API適用范圍以及入門篇總結)
- [7.7]-phalapi-進階篇1(三層結構Api,Domain,和Model)
- [7.8]-phalapi-進階篇2(DI依賴注入和單例模式)
- [7.9]-phalapi-進階篇3(自動加載和攔截器)
- [7.10]-phalapi-進階篇4(notorm進階以及事務操作)
- [7.11]-phalapi-進階篇5(數據庫讀寫分離)
- [7.12]-phalapi-進階篇6(解決大量數據存儲數據庫分表分庫拓展)
- [7.13]-phalapi-進階篇7(使用緩存以及用redis拓展解決實際問題)
- [7.14]-phalapi-進階篇8(PhalApi能帶來什么和進階篇總結)