




版權(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ì)自己和他人造成任何形式的傷害或損失。
最新文檔
- 跨國(guó)公司財(cái)務(wù)數(shù)據(jù)跨境保密協(xié)議
- 餐飲企業(yè)股權(quán)代持與解除協(xié)議樣本
- 縱隔腫瘤術(shù)后呼吸護(hù)理
- 2025年農(nóng)村自建房協(xié)議書(shū)
- 溝通培訓(xùn)心得
- 水嫩皮膚管理項(xiàng)目介紹
- 重癥護(hù)理健康宣教
- 頒獎(jiǎng)典禮動(dòng)態(tài)模板29
- 菌湯牦牛肉丸加工技術(shù)規(guī)范-編制說(shuō)明
- 愛(ài)眼日保護(hù)眼睛科學(xué)用眼預(yù)防近視28
- 2025屆河南省洛陽(yáng)市等兩地高三下學(xué)期三模歷史試題(含答案)
- 智能口罩設(shè)計(jì)優(yōu)化-洞察闡釋
- 2024年江蘇省東臺(tái)市事業(yè)單位公開(kāi)招聘教師崗考試題帶答案分析
- 2025年4月八大員-勞務(wù)員練習(xí)題庫(kù)與參考答案解析
- 2025年軍隊(duì)文職統(tǒng)一考試《專業(yè)科目》會(huì)計(jì)學(xué)試卷真題答案解析
- 農(nóng)村飲水安全工程可行性研究報(bào)告
- 人工智能與法律職業(yè)發(fā)展的潛在挑戰(zhàn)-洞察闡釋
- 2024-2025統(tǒng)編版一年級(jí)下冊(cè)道德與法治期末考試卷及參考答案
- 2025-2030年中國(guó)邊緣數(shù)據(jù)中心行業(yè)市場(chǎng)現(xiàn)狀調(diào)查及發(fā)展趨向研判報(bào)告
- 井岡山硒橙生產(chǎn)技術(shù)規(guī)程
- 四年級(jí)語(yǔ)文下冊(cè)期末分類復(fù)習(xí)日積月累與背誦
評(píng)論
0/150
提交評(píng)論