關(guān)于依賴注入在PHP框架中的應(yīng)用_第1頁(yè)
關(guān)于依賴注入在PHP框架中的應(yīng)用_第2頁(yè)
關(guān)于依賴注入在PHP框架中的應(yīng)用_第3頁(yè)
關(guān)于依賴注入在PHP框架中的應(yīng)用_第4頁(yè)
關(guān)于依賴注入在PHP框架中的應(yīng)用_第5頁(yè)
已閱讀5頁(yè),還剩30頁(yè)未讀, 繼續(xù)免費(fèi)閱讀

下載本文檔

版權(quán)說(shuō)明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請(qǐng)進(jìn)行舉報(bào)或認(rèn)領(lǐng)

文檔簡(jiǎn)介

1、關(guān)于依賴注入在PHP框架中的應(yīng)用現(xiàn)在的 PHP 應(yīng)用包含了很多對(duì)象。有的對(duì)象能幫你發(fā)送電子郵件,另一個(gè)可以幫你把數(shù)據(jù)持久化到數(shù)據(jù)庫(kù)中。在你的應(yīng)用中,你可能會(huì)創(chuàng)建一個(gè)管理產(chǎn)品庫(kù)存的對(duì)象,或者是一個(gè)處理第三方 API 數(shù)據(jù)的對(duì)象。這篇文章中,我們的關(guān)注這件事情:應(yīng)用做了很多事情,它組織了很多對(duì)象來(lái)處理每一個(gè)任務(wù)。在 PHP 的 Symfony 2 框架中,有一個(gè)特殊的對(duì)象,幫助你實(shí)例化、組織和獲取應(yīng)用中的那一系列的對(duì)象。它叫 Service Container(服務(wù)容器),可以讓你標(biāo)準(zhǔn)化和集中化地創(chuàng)建應(yīng)用中對(duì)象。容器讓生活簡(jiǎn)化,它速度很快,包含的架構(gòu)思想促進(jìn)代碼的重用和解耦。所有 Symfony

2、2 的核心的類都使用容器,容器為框架的速度和可擴(kuò)展性做了最大的貢獻(xiàn)。先來(lái)了解下什么是 Service。簡(jiǎn)單的說(shuō),一個(gè) Service 就是任何的可以完成某類“全局”任務(wù)的 PHP 對(duì)象。一個(gè) Service 是一個(gè) PHP 對(duì)象的通用性的術(shù)語(yǔ),這個(gè)對(duì)象能執(zhí)行特定的任務(wù),通常被“全局”地使用,比如一個(gè)數(shù)據(jù)庫(kù)連接的對(duì)象,或者一個(gè)能發(fā)送電子郵件的對(duì)象。如果擁有很多松耦合的 Service,我們就說(shuō)這個(gè)應(yīng)用遵循了 SOA(面向服務(wù)的架構(gòu))。創(chuàng)建一個(gè) Service 很簡(jiǎn)單,你只要為那份能完成特定任務(wù)的代碼寫個(gè)類,就 OK 了。一般來(lái)說(shuō),PHP 對(duì)象如果要成為 Service,必須要在應(yīng)用中被全局的使用

3、。比如一個(gè) Mailer Service 被全局的用于發(fā)送電子郵件,但是由 Mailer 發(fā)送的郵件內(nèi)容對(duì)象(每次的內(nèi)容都不同)就不是 Service。既然 Service 這么容易創(chuàng)建,那有啥了不起的呢?如果你開(kāi)始考慮將應(yīng)用中的每個(gè)功能都分離開(kāi)來(lái),你就能開(kāi)始感受 Service 的好處了。因?yàn)槊總€(gè) Service 只做一個(gè)工作,你在任何地方都可以輕松地獲得并使用它們的功能。每個(gè) Service 也能更容易的被測(cè)試和配置,因?yàn)樵趹?yīng)用中它們是互相分離的。將你的應(yīng)用組織成一系列獨(dú)立的 Service 的類,也是面向?qū)ο缶幊痰淖罴褜?shí)踐之一。這種技能在任何開(kāi)發(fā)語(yǔ)言中都是好程序員的標(biāo)志。什么是 Serv

4、ice Container。Service Container 也叫 Dependency Injection Container(依賴注入容器),就是一個(gè)簡(jiǎn)單的 PHP 對(duì)象,管理著 Service 們的實(shí)例化。假設(shè)你有個(gè)發(fā)送電子郵件的 PHP 類。如果不用 Service Container,在你需要它時(shí),都必須手工地創(chuàng)建對(duì)象。這也算簡(jiǎn)單。但是,如果你不想重復(fù)地去配置它,就可以把它作為 Service。當(dāng)你需要?jiǎng)?chuàng)建一個(gè) Service,它依賴了 Service Container 中一個(gè)或幾個(gè)其他的 Service 們時(shí),你才會(huì)意識(shí)到容器的強(qiáng)大。假設(shè)你的一個(gè)新的 Service,依賴了發(fā)送

5、電子郵件的 Service。只要在新的 Service 配置中將發(fā)送電子郵件的 Service 設(shè)為參數(shù)即可,如果你的這個(gè) Service 后來(lái)做了改動(dòng),需要再依賴一個(gè) Service,只需要改下配置,增加參數(shù)即可。對(duì)應(yīng)到依賴注入模式,其實(shí) Service Container 就是注入器;Service A 依賴 Service B,前者是依賴者,后者是被依賴者;被依賴者的接口一般就是依賴的定義。這次設(shè)計(jì)模式解決的是整個(gè)框架的架構(gòu)問(wèn)題,解決了:功能間的松耦合、框架的擴(kuò)展性,運(yùn)行效率也高。其實(shí)還是蠻羨慕學(xué) Java 的同學(xué),很早就接觸一些好的設(shè)計(jì)和應(yīng)用,比如:Spring 框架。當(dāng)然現(xiàn)在 PHP

6、 的新的框架層出不窮,也借鑒各種好的思想。面包和牛奶已經(jīng)有了,可以吃了??碙aravel的IoC容器文檔只是介紹實(shí)例,但是沒(méi)有說(shuō)原理,之前用MVC框架都沒(méi)有在意這個(gè)概念,無(wú)意中在phalcon的文檔中看到這個(gè)詳細(xì)的介紹,感覺(jué)豁然開(kāi)朗,復(fù)制粘貼過(guò)來(lái),主要是好久沒(méi)有寫東西了,現(xiàn)在確實(shí)很懶變得!首先,我們假設(shè),我們要開(kāi)發(fā)一個(gè)組件命名為SomeComponent。這個(gè)組件中現(xiàn)在將要注入一個(gè)數(shù)據(jù)庫(kù)連接。在這個(gè)例子中,數(shù)據(jù)庫(kù)連接在component中被創(chuàng)建,這種方法是不切實(shí)際的,這樣做的話,我們將不能改變數(shù)據(jù)庫(kù)連接參數(shù)及數(shù)據(jù)庫(kù)類型等一些參數(shù)。php view plaincopy1. <?p

7、hp  2.   3. class SomeComponent  4.   5.   6.     /* 7.      * The instantiation of the connection is hardcoded inside 8.     

8、0;* the component so is difficult to replace it externally 9.      * or change its behavior 10.      */  11.     public function someDb

9、Task()  12.       13.         $connection = new Connection(array(  14.             "host" => "localhost&quo

10、t;,  15.             "username" => "root",  16.             "password" => "secret",  

11、;17.             "dbname" => "invo"  18.         );  19.   20.         / .  21. &#

12、160;     22.   23.   24.   25. $some = new SomeComponent();  26. $some->someDbTask();  為了解決上面所說(shuō)的問(wèn)題,我們需要在使用前創(chuàng)建一個(gè)外部連接,并注入到容器中。就目前而言,這看起來(lái)是一個(gè)很好的解決方案:php view plaincopy1. <?php  2.   3

13、. class SomeComponent  4.   5.   6.     protected $_connection;  7.   8.     /* 9.      * Sets the connection externally 10.    &#

14、160; */  11.     public function setConnection($connection)  12.       13.         $this->_connection = $connection;  14.      

15、 15.   16.     public function someDbTask()  17.       18.         $connection = $this->_connection;  19.   20.      

16、   / .  21.       22.   23.   24.   25. $some = new SomeComponent();  26.   27. /Create the connection  28. $connection = new Connection(arr

17、ay(  29.     "host" => "localhost",  30.     "username" => "root",  31.     "password" => "secret",  

18、32.     "dbname" => "invo"  33. );  34.   35. /Inject the connection in the component  36. $some->setConnection($connection);  37.   38. $some->someDbTask()

19、;  現(xiàn)在我們來(lái)考慮一個(gè)問(wèn)題,我們?cè)趹?yīng)用程序中的不同地方使用此組件,將多次創(chuàng)建數(shù)據(jù)庫(kù)連接。使用一種類似全局注冊(cè)表的方式,從這獲得一個(gè)數(shù)據(jù)庫(kù)連接實(shí)例,而不是使用一次就創(chuàng)建一次。php view plaincopy1. <?php  2.   3. class Registry  4.   5.   6.     /* 7.      * Ret

20、urns the connection 8.      */  9.     public static function getConnection()  10.       11.        return new Connection(array(&#

21、160; 12.             "host" => "localhost",  13.             "username" => "root",  14. &

22、#160;           "password" => "secret",  15.             "dbname" => "invo"  16.    

23、     );  17.       18.   19.   20.   21. class SomeComponent  22.   23.   24.     protected $_connection;  25.   26.  &#

24、160;  /* 27.      * Sets the connection externally 28.      */  29.     public function setConnection($connection)  30.       

25、0; $this->_connection = $connection;  31.       32.   33.     public function someDbTask()  34.       35.         $connect

26、ion = $this->_connection;  36.   37.         / .  38.       39.   40.   41.   42. $some = new SomeComponent();  43.   

27、;44. /Pass the connection defined in the registry  45. $some->setConnection(Registry:getConnection();  46.   47. $some->someDbTask();  現(xiàn)在,讓我們來(lái)想像一下,我們必須在組件中實(shí)現(xiàn)兩個(gè)方法,首先需要?jiǎng)?chuàng)建一個(gè)新的數(shù)據(jù)庫(kù)連接,第二個(gè)總是獲得一個(gè)共享連接:php view plaincopy1. <?p

28、hp  2.   3. class Registry  4.   5.   6.     protected static $_connection;  7.   8.     /* 9.      * Creates a connection 10

29、.      */  11.     protected static function _createConnection()  12.       13.         return new Connection(array(  14.  &#

30、160;          "host" => "localhost",  15.             "username" => "root",  16.     

31、;        "password" => "secret",  17.             "dbname" => "invo"  18.       

32、0; );  19.       20.   21.     /* 22.      * Creates a connection only once and returns it 23.      */  24.  &

33、#160;  public static function getSharedConnection()  25.       26.         if (self:$_connection=null)  27.             

34、$connection = self:_createConnection();  28.             self:$_connection = $connection;  29.           30.        

35、; return self:$_connection;  31.       32.   33.     /* 34.      * Always returns a new connection 35.      */  36.  

36、60;  public static function getNewConnection()  37.       38.         return self:_createConnection();  39.       40.   41.   42.

37、  43. class SomeComponent  44.   45.   46.     protected $_connection;  47.   48.     /* 49.      * Sets the connection externally 50.

38、     */  51.     public function setConnection($connection)  52.         $this->_connection = $connection;  53.       54.  

39、0;55.     /* 56.      * This method always needs the shared connection 57.      */  58.     public function someDbTask()  59.  

40、60;    60.         $connection = $this->_connection;  61.   62.         / .  63.       64.   65.   

41、60; /* 66.      * This method always needs a new connection 67.      */  68.     public function someOtherDbTask($connection)  69.    &

42、#160;  70.   71.       72.   73.   74.   75. $some = new SomeComponent();  76.   77. /This injects the shared connection  78. $some->setConnection(Regis

43、try:getSharedConnection();  79.   80. $some->someDbTask();  81.   82. /Here, we always pass a new connection as parameter  83. $some->someOtherDbTask(Registry:getConnection();  到此為止,我們已經(jīng)看到了如何使用依

44、賴注入解決我們的問(wèn)題。不是在代碼內(nèi)部創(chuàng)建依賴關(guān)系,而是讓其作為一個(gè)參數(shù)傳遞,這使得我們的程序更容易維護(hù),降低程序代碼的耦合度,實(shí)現(xiàn)一種松耦合。但是從長(zhǎng)遠(yuǎn)來(lái)看,這種形式的依賴注入也有一些缺點(diǎn)。例如,如果組件中有較多的依賴關(guān)系,我們需要?jiǎng)?chuàng)建多個(gè)setter方法傳遞,或創(chuàng)建構(gòu)造函數(shù)進(jìn)行傳遞。另外,每次使用組件時(shí),都需要?jiǎng)?chuàng)建依賴組件,使代碼維護(hù)不太易,我們編寫的代碼可能像這樣:php view plaincopy1. <?php  2.   3. /Create the dependencies or re

45、trieve them from the registry  4. $connection = new Connection();  5. $session = new Session();  6. $fileSystem = new FileSystem();  7. $filter = new Filter();  8. $selec

46、tor = new Selector();  9.   10. /Pass them as constructor parameters  11. $some = new SomeComponent($connection, $session, $fileSystem, $filter, $selector);  12.   13. / .

47、0;or using setters  14.   15. $some->setConnection($connection);  16. $some->setSession($session);  17. $some->setFileSystem($fileSystem);  18. $some->setFilter($filter);  19. $some->setSelector($selector); 

48、60;我想,我們不得不在應(yīng)用程序的許多地方創(chuàng)建這個(gè)對(duì)象。如果你不需要依賴的組件后,我們又要去代碼注入部分移除構(gòu)造函數(shù)中的參數(shù)或者是setter方法。為了解決這個(gè)問(wèn)題,我們?cè)俅畏祷厝ナ褂靡粋€(gè)全局注冊(cè)表來(lái)創(chuàng)建組件。但是,在創(chuàng)建對(duì)象之前,它增加了一個(gè)新的抽象層:php view plaincopy1. <?php  2.   3. class SomeComponent  4.   5.   6.     / . &

49、#160;7.   8.     /* 9.      * Define a factory method to create SomeComponent instances injecting its dependencies 10.      */  11.   &

50、#160; public static function factory()  12.       13.   14.         $connection = new Connection();  15.         $session

51、0;= new Session();  16.         $fileSystem = new FileSystem();  17.         $filter = new Filter();  18.        &#

52、160;$selector = new Selector();  19.   20.         return new self($connection, $session, $fileSystem, $filter, $selector);  21.       22.   23.

53、  這一刻,我們好像回到了問(wèn)題的開(kāi)始,我們正在創(chuàng)建組件內(nèi)部的依賴,我們每次都在修改以及找尋一種解決問(wèn)題的辦法,但這都不是很好的做法。一種實(shí)用和優(yōu)雅的來(lái)解決這些問(wèn)題,是使用容器的依賴注入,像我們?cè)谇懊婵吹降?,容器作為全局注?cè)表,使用容器的依賴注入做為一種橋梁來(lái)解決依賴可以使我們的代碼耦合度更低,很好的降低了組件的復(fù)雜性:php view plaincopy1. <?php  2.   3. class SomeComponent  4.   5.   

54、6.     protected $_di;  7.   8.     public function _construct($di)  9.       10.         $this->_di = $di;  11.  

55、60;    12.   13.     public function someDbTask()  14.       15.   16.         / Get the connection service  17.  &

56、#160;      / Always returns a new connection  18.         $connection = $this->_di->get('db');  19.   20.       21.  

57、; 22.     public function someOtherDbTask()  23.       24.   25.         / Get a shared connection service,  26.     

58、60;   / this will return the same connection everytime  27.         $connection = $this->_di->getShared('db');  28.   29.      

59、0;  /This method also requires a input filtering service  30.         $filter = $this->_db->get('filter');  31.   32.       33. 

60、60; 34.   35.   36. $di = new PhalconDI();  37.   38. /Register a "db" service in the container  39. $di->set('db', function()  40.     return&#

61、160;new Connection(array(  41.         "host" => "localhost",  42.         "username" => "root",  43.    

62、;     "password" => "secret",  44.         "dbname" => "invo"  45.     );  46. );  47.   48. /Regis

63、ter a "filter" service in the container  49. $di->set('filter', function()  50.     return new Filter();  51. );  52.   53. /Register a "session"

64、; service in the container  54. $di->set('session', function()  55.     return new Session();  56. );  57.   58. /Pass the service container as unique par

65、ameter  59. $some = new SomeComponent($di);  60.   61. $some->someTask();  現(xiàn)在,該組件只有訪問(wèn)某種service的時(shí)候才需要它,如果它不需要,它甚至不初始化,以節(jié)約資源。該組件是高度解耦。他們的行為,或者說(shuō)他們的任何其他方面都不會(huì)影響到組件本身。我們的實(shí)現(xiàn)辦法PhalconDI 是一個(gè)實(shí)現(xiàn)了服務(wù)的依賴注入功能的組件,它本身也是一個(gè)容器。由于Phalcon高度解耦,PhalconDI 是框架用來(lái)集成其他組件

66、的必不可少的部分,開(kāi)發(fā)人員也可以使用這個(gè)組件依賴注入和管理應(yīng)用程序中不同類文件的實(shí)例?;旧希@個(gè)組件實(shí)現(xiàn)了 Inversion of Control 模式?;诖?,對(duì)象不再以構(gòu)造函數(shù)接收參數(shù)或者使用setter的方式來(lái)實(shí)現(xiàn)注入,而是直接請(qǐng)求服務(wù)的依賴注入。這就大大降低了整體程序的復(fù)雜性,因?yàn)橹挥幸粋€(gè)方法用以獲得所需要的一個(gè)組件的依賴關(guān)系。此外,這種模式增強(qiáng)了代碼的可測(cè)試性,從而使它不容易出錯(cuò)。在容器中注冊(cè)服務(wù)¶框架本身或開(kāi)發(fā)人員都可以注冊(cè)服務(wù)。當(dāng)一個(gè)組件A要求調(diào)用組件B(或它的類的一個(gè)實(shí)例),可以從容器中請(qǐng)求調(diào)用組件B,而不是創(chuàng)建組件B的一個(gè)實(shí)例。這種工作方式為我們提供了許多優(yōu)點(diǎn):

67、我們可以更換一個(gè)組件,從他們本身或者第三方輕松創(chuàng)建。在組件發(fā)布之前,我們可以充分的控制對(duì)象的初始化,并對(duì)對(duì)象進(jìn)行各種設(shè)置。我們可以使用統(tǒng)一的方式從組件得到一個(gè)結(jié)構(gòu)化的全局實(shí)例服務(wù)可以通過(guò)以下幾種方式注入到容器:php view plaincopy1. <?php  2.   3. /Create the Dependency Injector Container  4. $di = new PhalconDI();  5. 

68、60; 6. /By its class name  7. $di->set("request", 'PhalconHttpRequest');  8.   9. /Using an anonymous function, the instance will lazy loaded  10. $di->set("request&q

69、uot;, function()  11.     return new PhalconHttpRequest();  12. );  13.   14. /Registering directly an instance  15. $di->set("request", new PhalconHttpRequest();  16.

70、   17. /Using an array definition  18. $di->set("request", array(  19.     "className" => 'PhalconHttpRequest'  20. );  在上面的例子中,當(dāng)向框架請(qǐng)求訪問(wèn)一個(gè)請(qǐng)求數(shù)據(jù)時(shí),它將首先確定容器中是否存在這個(gè)”reqeus

71、t”名稱的服務(wù)。容器會(huì)反回一個(gè)請(qǐng)求數(shù)據(jù)的實(shí)例,開(kāi)發(fā)人員最終得到他們想要的組件。在上面示例中的每一種方法都有優(yōu)缺點(diǎn),具體使用哪一種,由開(kāi)發(fā)過(guò)程中的特定場(chǎng)景來(lái)決定的。用一個(gè)字符串來(lái)設(shè)定一個(gè)服務(wù)非常簡(jiǎn)單,但缺少靈活性。設(shè)置服務(wù)時(shí),使用數(shù)組則提供了更多的靈活性,而且可以使用較復(fù)雜的代碼。lambda函數(shù)是兩者之間一個(gè)很好的平衡,但也可能導(dǎo)致更多的維護(hù)管理成本。PhalconDI 提供服務(wù)的延遲加載。除非開(kāi)發(fā)人員在注入服務(wù)的時(shí)候直接實(shí)例化一個(gè)對(duì)象,然后存存儲(chǔ)到容器中。在容器中,通過(guò)數(shù)組,字符串等方式存儲(chǔ)的服務(wù)都將被延遲加載,即只有在請(qǐng)求對(duì)象的時(shí)候才被初始化。php view plaincopy

72、1. <?php  2.   3. /Register a service "db" with a class name and its parameters  4. $di->set("db", array(  5.     "className" => "P

73、halconDbAdapterPdoMysql",  6.     "parameters" => array(  7.           "parameter" => array(  8.         

74、0;      "host" => "localhost",  9.                "username" => "root",  10.      &#

75、160;         "password" => "secret",  11.                "dbname" => "blog"  12.   &

76、#160;       )  13.     )  14. );  15.   16. /Using an anonymous function  17. $di->set("db", function()  18.     return new

77、0;PhalconDbAdapterPdoMysql(array(  19.          "host" => "localhost",  20.          "username" => "root",  21. &#

78、160;        "password" => "secret",  22.          "dbname" => "blog"  23.     );  24. );  

79、;以上這兩種服務(wù)的注冊(cè)方式產(chǎn)生相同的結(jié)果。然后,通過(guò)數(shù)組定義的,在后面需要的時(shí)候,你可以修改服務(wù)參數(shù):php view plaincopy1. <?php  2.   3. $di->setParameter("db", 0, array(  4.     "host" => "localhost",  5.    &#

80、160;"username" => "root",  6.     "password" => "secret"  7. );  從容器中獲得服務(wù)的最簡(jiǎn)單方式就是使用”get”方法,它將從容器中返回一個(gè)新的實(shí)例:php view plaincopy1. <?php   2. $request = $d

81、i->get("request");  或者通過(guò)下面這種魔術(shù)方法的形式調(diào)用:php view plaincopy1. <?php  2.   3. $request = $di->getRequest();  PhalconDI 同時(shí)允許服務(wù)重用,為了得到一個(gè)已經(jīng)實(shí)例化過(guò)的服務(wù),可以使用 getShared() 方法的形式來(lái)獲得服務(wù)。具體的 PhalconHttpRequest 請(qǐng)求示例:php view plaincopy1. <

82、?php  2.   3. $request = $di->getShared("request");  參數(shù)還可以在請(qǐng)求的時(shí)候通過(guò)將一個(gè)數(shù)組參數(shù)傳遞給構(gòu)造函數(shù)的方式:php view plaincopy1. <?php  2.   3. $component = $di->get("MyComponent", array("some-parameter",&

83、#160;"other")  首先先別追究這個(gè)設(shè)計(jì)模式的定義,否則你一定會(huì)被說(shuō)的云里霧里,筆者就是深受其害,百度了N多文章,都是從理論角度來(lái)描述,充斥著大量的生澀詞匯,要么就是java代碼描述的,也生澀。不管怎么樣,總算弄清楚一些了,下面就以php的角度來(lái)描述一下依賴注入這個(gè)概念。先假設(shè)我們這里有一個(gè)類,類里面需要用到數(shù)據(jù)庫(kù)連接,按照最最原始的辦法,我們可能是這樣寫這個(gè)類的:1. class example 2.     3.     private

84、60;$_db;4.5.     function _construct()6.         include "./Lib/Db.php"7.         $this->_db = new Db("localhost","root","123456",&q

85、uot;test");8.     9.10.     function getList()11.         $this->_db->query(".");/這里具體sql語(yǔ)句就省略不寫了12.     13.  復(fù)制代碼過(guò)程:在構(gòu)造函數(shù)里先將數(shù)據(jù)庫(kù)類文件include進(jìn)來(lái);然后又通過(guò)new Db并傳入數(shù)據(jù)庫(kù)連接信息實(shí)例化db類;

86、之后getList方法就可以通過(guò)$this->_db來(lái)調(diào)用數(shù)據(jù)庫(kù)類,實(shí)現(xiàn)數(shù)據(jù)庫(kù)操作。看上去我們實(shí)現(xiàn)了想要的功能,但是這是一個(gè)噩夢(mèng)的開(kāi)始,以后example1,example2,example3.越來(lái)越多的類需要用到db組件,如果都這么寫的話,萬(wàn)一有一天數(shù)據(jù)庫(kù)密碼改了或者db類發(fā)生變化了,豈不是要回頭修改所有類文件?ok,為了解決這個(gè)問(wèn)題,工廠模式出現(xiàn)了,我們創(chuàng)建了一個(gè)Factory方法,并通過(guò)Factory:getDb()方法來(lái)獲得db組件的實(shí)例:1. class Factory 2.     public stati

87、c function getDb()3.         include "./Lib/Db.php"4.         return new Db("localhost","root","123456","test");5.     6. 

88、60;復(fù)制代碼sample類變成:1. class example 2.     3.     private $_db;4.5.     function _construct()6.         $this->_db = Factory:getDb();7.     8.9. 

89、0;   function getList()10.         $this->_db->query(".");/這里具體sql語(yǔ)句就省略不寫了11.     12.  復(fù)制代碼這樣就完美了嗎?再次想想一下以后example1,example2,example3.所有的類,你都需要在構(gòu)造函數(shù)里通過(guò)Factory:getDb();獲的一個(gè)Db實(shí)例,實(shí)際上你由原來(lái)的直接與Db類的耦合變?yōu)榱撕虵a

90、ctory工廠類的耦合,工廠類只是幫你把數(shù)據(jù)庫(kù)連接信息給包裝起來(lái)了,雖然當(dāng)數(shù)據(jù)庫(kù)信息發(fā)生變化時(shí)只要修改Factory:getDb()方法就可以了,但是突然有一天工廠方法需要改名,或者getDb方法需要改名,你又怎么辦?當(dāng)然這種需求其實(shí)還是很操蛋的,但有時(shí)候確實(shí)存在這種情況,一種解決方式是:我們不從example類內(nèi)部實(shí)例化Db組件,我們依靠從外部的注入,什么意思呢?看下面的例子:1. class example 2.     private $_db;3.     function&#

91、160;getList()4.         $this->_db->query(".");/這里具體sql語(yǔ)句就省略不寫了5.     6.     /從外部注入db連接7.     function setDb($connection)8.         $this-&

92、gt;_db = $connection;9.     10.  11.12.  /調(diào)用13. $example = new example();14. $example->setDb(Factory:getDb();/注入db連接15. $example->getList();復(fù)制代碼這樣一來(lái),example類完全與外部類解除耦合了,你可以看到Db類里面已經(jīng)沒(méi)有工廠方法或Db類的身影了。我們通過(guò)從外部調(diào)用example類的setDb方法,將連接實(shí)例直接注入進(jìn)去。這樣exa

93、mple完全不用關(guān)心db連接怎么生成的了。這就叫依賴注入,實(shí)現(xiàn)不是在代碼內(nèi)部創(chuàng)建依賴關(guān)系,而是讓其作為一個(gè)參數(shù)傳遞,這使得我們的程序更容易維護(hù),降低程序代碼的耦合度,實(shí)現(xiàn)一種松耦合。這還沒(méi)完,我們?cè)偌僭O(shè)example類里面除了db還要用到其他外部類,我們通過(guò):1. $example->setDb(Factory:getDb();/注入db連接2. $example->setFile(Factory:getFile();/注入文件處理類3. $example->setImage(Factory:getImage();/注入Image處理類4.  .復(fù)制代碼我們沒(méi)完沒(méi)了

94、的寫這么多set?累不累?ok,為了不用每次寫這么多行代碼,我們又去弄了一個(gè)工廠方法:1. class Factory 2.     public static function getExample()3.         $example = new example();4.         $example-&g

95、t;setDb(Factory:getDb();/注入db連接5.         $example->setFile(Factory:getFile();/注入文件處理類6.         $example->setImage(Factory:getImage();/注入Image處理類7.         return $expa

96、mple;8.     9.10.  復(fù)制代碼實(shí)例化example時(shí)變?yōu)椋?. $example=Factory:getExample();2. $example->getList();復(fù)制代碼似乎完美了,但是怎么感覺(jué)又回到了上面第一次用工廠方法時(shí)的場(chǎng)景?這確實(shí)不是一個(gè)好的解決方案,所以又提出了一個(gè)概念:容器,又叫做IoC容器、DI容器。我們本來(lái)是通過(guò)setXXX方法注入各種類,代碼很長(zhǎng),方法很多,雖然可以通過(guò)一個(gè)工廠方法包裝,但是還不是那么爽,好吧,我們不用setXXX方法了,這樣也就不用工廠方法二次包裝了,那么我們還怎么實(shí)現(xiàn)依賴注入呢?這里我們引入一個(gè)約定:在example類的構(gòu)造函數(shù)里傳入一個(gè)名為Di $di的參數(shù),如下:1. class example 2.     private $_di;3.     fu

溫馨提示

  • 1. 本站所有資源如無(wú)特殊說(shuō)明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請(qǐng)下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請(qǐng)聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁(yè)內(nèi)容里面會(huì)有圖紙預(yù)覽,若沒(méi)有圖紙預(yù)覽就沒(méi)有圖紙。
  • 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
  • 5. 人人文庫(kù)網(wǎng)僅提供信息存儲(chǔ)空間,僅對(duì)用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對(duì)用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對(duì)任何下載內(nèi)容負(fù)責(zé)。
  • 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請(qǐng)與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時(shí)也不承擔(dān)用戶因使用這些下載資源對(duì)自己和他人造成任何形式的傷害或損失。

評(píng)論

0/150

提交評(píng)論