首頁 > 後端開發 > php教程 > PHP 依賴注入(DI) 和 控制反轉(IoC)實例教程

PHP 依賴注入(DI) 和 控制反轉(IoC)實例教程

零下一度
發布: 2023-03-10 17:22:01
原創
2449 人瀏覽過

要理解PHP 依賴注入 與 控制反轉 兩個概念,就必須先搞清楚如下的兩個問題:

  • DI —— Dependency Injection 依賴注入

  • IoC —— Inversion of Control 控制反轉

什麼是依賴注入

沒有你我就活不下去,那麼,你就是我的依賴。 說白了就是:

不是我自己的,卻是我需要的,都是我所依賴的。一切需要外部提供的,都是需要依賴注入的。

依賴注入範例

 
1
##2
# 3
4
5
6
7
8
9
#10
11
12
13
14
15
16
17
18
class Boy {
  
protected $girl
;
 
  
public 
function
 
__construct(Girl 
$girl) {
    $this
# ->girl = 
$girl
;
#  ##}
##。 #}
######class### ###Girl {############  ######... ############}######### ##########$boy### ###= ######new#### ###Boy();  ######// Error; Boy must have girlfriend!######### ########// 所以,必須要給他一個女朋友才行############$girl### ###= ########## ###Girl();########################################################################################### #########$boy### ###= ######new#### ###Boy(######$girl######); # #####// Right! So Happy!######################

從上述程式碼我們可以看到Boy強依賴Girl必須在建構時注入Girl的實例才行。

那麼為什麼要有依賴注入這個概念,依賴注入到底解決了什麼問題?

我們將上述程式碼修正一下我們初學時都寫過的程式碼:

1
2
3
4
#5
6
7
class Boy {
  protected $girl#;
 
  public function __construct() {
#    $this->girl = new #Girl();

  }這種方式與前面的方式有什麼不同呢? protected ###;######### #########  ######public### ###function### ###__construct() {############      #######//  $this->girl = new Girl();  // sorry...########### #      ######$this######->girl = ######new### ####LoliGirl();############  ####LoliGirl();############ #####}############}######################

某天 Boy迷戀上了禦姐....Boy 好煩。 。 。

是不是感覺不太好?每次遇到真心相待的人卻要這麼的折磨自己。 。 。

Boy說,我要變的強大一點。我不想被改來改去的!

好吧,我們讓Boy強大一點:

}
我們會發現
Boy的女朋友被我們硬編碼到Boy的身體裡去了。 。 。 每次Boy
重生自己想換個類型的女朋友都要把自己扒光才行。
某天
Boy特別喜歡一個LoliGirl
 ,很想讓她當自己的女朋友。 。 。怎麼辦? 重生自己。 。 。扒開自己。 。 。把
Girl
丟了。 。 。把 
LoliGirl塞進去。 。 。
1#23##4
#5
678910
##11
12
class LoliGirl { }
 class 
Boy {
  
##1
#2
3
4
#5
6
7
##8
10
11
12
#13
#14
#15
17
18
19
#20
#21
#22
##23
24
25
#interface
 
Girl {
#  
// Boy need knows that I have some abilities.
##}## 
class LoliGril implement Girl {
#  
// I will implement Girl's abilities.
## } class Vixen implement Girl {  
#// Vixen definitely is a girl, do not doubt it.} class
 
Boy {  
protected $girl
;
 
########## ###  ######public### ###function### ###__construct(Girl ######$girl#####) {############################################################################################################################################ ####    ######$this######->girl = ######$girl#####;######################################################################################### ######}############}######### #########$loliGirl### ###= ### ###new### ###LoliGirl();############$vixen### ###= ######new### ###Vixen( );######### #########$boy### ###= ######new### ###Boy(####### $loliGirl######);######
$boy new Boy($vixen);

Boy 很高興,終於可以不用扒開自己就可以體驗不同的人生了。 。 。 So Happy!

依賴注入方式

1、建構器注入

1
2
3
4
#5
##6
##7
#8
<?php
#class
 Book {
  
private $db_conn;
 
#  
public function __construct($db_conn##) {    
$this->db_conn = $db_conn##;
#}
}
#

2、setter注入

##

小結:

因為大多數應用程式都是由兩個或更多的類別透過彼此合作來實現業務邏輯,這使得每個物件都需要取得與其合作的物件(也就是它所依賴的物件)的引用。如果這個獲取過程要靠自身實現,那麼將導致程式碼高度耦合並且難以維護和調試。

所以有了依賴注入的概念,依賴注入解決了以下問題:

  • 依賴之間的解耦

  • 單元測試,方便Mock

上面兩個方法程式碼很清晰,但是當我們需要注入很多個依賴時,意味著又要增加很多行,會比較難以管理。

比較好的解決方法是 建立一個class作為所有依賴關係的container,在這個class中可以存放、建立、取得、尋找需要的依賴關係。先來了解一下IOC的概念

控制反轉(Inversion Of Control, IOC)

控制反轉 是物件導向程式設計中的一種設計原則,可以用來減低電腦程式碼之間的耦合度。其中最常見的方式叫做 依賴注入(Dependency Injection, DI), 還有一種叫"依賴查找"(Dependency Lookup)。透過控制反轉,物件在被創建的時候,由一個調控系統內所有物件的外界實體,將其所依賴的物件的引用傳遞給它。也可以說,依賴被注入到物件中。

1
3
4
#5
6
7
##8
# 9
10
11
12
#13
#14
#15
##16
17
18
19
20
21
22
23
24
25
26
27
<?php </div>##class<div class="line number2 index1 alt1"> <code class="php keyword">#Book {
#    
private #$db;
    
私有#$檔案;## 
    
函數 ##setdb($db) {
        $this->db = $db;
    ##  ## }## ##    
#function
setfile($file
) {
        
#$this
->file = ##$file;
## ##########
檔{
}
#db { 
測驗{
    
$book
 
 Book( );
#
    $book##->setdb(new db()); #    $book->setfile(new file()); #}
#;
1
#2
3
##4
#5
6
7
8
9
10
##11
12
13
14
#<?php
 
##class Ioc {
    protected $db_conn#;
 
    #public static function make_book() {
 
function make_book() {        #$new_book 
##new
 Book(); Book();#        
$new_book->set_db(self::</div>$db_conn<div class="line number10 index9 alt1"> <code class="php spaces">#);#        
//...
        
//...//其他的依賴注入
        ## 
$new_book
#;
#$new_book
###    ######}#############}###############################################################################################################

此時,如果取得一個book實例,只需要執行$newone = Ioc::makebook();

以上是container的一個具體實例,最好還是不要把具體的某個依賴注入寫成方法,採用registry註冊,get取得比較好

#}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
##15
16
#17
18
19
20
21
22
23
#24
25
26
27
28
29
#30
31
32
33
34
#35
#36
#37
# 38
39
4041
#42#43
#44#45 46
47
#<?php##/* *
 ##* 控制反轉類別
 ##*/
class
 Ioc {
    
/**     * @var array 註冊的依賴陣列     #*/
    
protected static 
$registry
 
();
 
    
/**
     
* 增加一個resolve (匿名函數)到registry 陣列中
#     ######*############     ###############   ####* @param string  $name    依賴標識############     ######* @param Closure $resolve 一個匿名函數,用來建立一個實例######實例#######namp
     * @return void
#     */
#   */> public static functionregister($name, 閉包
) {        靜態::#$registry$name] = 
$resolve;
    
 
    /**
     * 回傳一個實例
     #*     * @param string $name 依賴的標識
     * @return mixed
     * @throws \Exception
#     */##     static functionresolve(
$name
) {#        if## #(static::registered(
$name
$name##::registered(##$name)) {             $名稱#$registry [##$name
];
            return##return##return1
#$name
();
        
}
## ##        throw new \Exception(
"沒有使用該名稱註冊"
#);
#    
}
 
    
#/**#     ## ####* 查詢某個依賴實例是否存在######
     *
     * @param string $name
##   # ##* @return bool
     
*/
    
#public#    #10 # static function registered($name
) {
        #        #return array_key_exists($namestatic#::
$registry);
    }
現在就可以透過以下方式註冊和注入一個10
1
2
3
#4
#5
##6
7
8
9
#11
<?phpIoc::register("book"
function
 () {    $book 
#new## 
#Book();    $book#->setdb('db'
##);
    $book->setfile('file'
);
    return $book##;
});
 
// 注入依賴
#$book = Ioc::resolve('book');
####

問題總結

1、參與者都有誰?

答:一般有三方參與者,一個是某個物件;一個是IoC/DI的容器;另一個是某個物件的外在資源。又要名詞解釋一下,某個物件指的就是任意的、普通的Java物件; IoC/DI的容器簡單點說就是指用來實作IoC/DI功能的一個框架程式;物件的外部資源指的就是對象需要的,但是是從物件外部取得的,都統稱資源,例如:物件需要的其它物件、或者是物件需要的檔案資源等等。

2、依賴:誰依賴誰?為什麼會有依賴?

答:某個物件依賴IoC/DI的容器。依賴是不可避免的,在一個專案中,各個類別之間有各種各樣的關係,不可能全部完全獨立,這就形成了依賴。傳統的開發是使用其他類別時直接調用,這會形成強耦合,這是要避免的。依賴注入借用容器轉移了被依賴物件實作解耦。

3、注入:誰注入於誰?到底注入什麼?

答:透過容器向物件注入其所需的外部資源

4、控制反轉:誰控制誰?控制什麼?為什麼叫反轉?

答案:IoC/DI的容器控制對象,主要是控制對象實例的建立。反轉是相對於正向而言的,那麼什麼算是正向的呢?考慮一下常規情況下的應用程序,如果要在A裡面使用C,你會怎麼做呢?當然是直接去創建C的對象,也就是說,是在A類中主動去取得所需要的外部資源C,這種情況稱為正向的。那什麼是反向呢?就是A類別不再主動去取得C,而是被動等待,等待IoC/DI的容器取得一個C的實例,然後反向的注入到A類別中。

5、依賴注入和控制反轉是同一概念嗎?

答:從上面可以看出:依賴注入是從應用程式的角度在描述,可以把依賴注入描述完整點:應用程式依賴容器來建立並註入它所需要的外部資源;而控制反轉是從容器的角度在描述,描述完整點:容器控制應用程序,由容器反向的向應用程式註入應用程式所需的外部資源。

以上是PHP 依賴注入(DI) 和 控制反轉(IoC)實例教程的詳細內容。更多資訊請關注PHP中文網其他相關文章!

相關標籤:
來源:php.cn
上一篇:PHP7中有哪些特性 下一篇:PHP的初步理解--封裝、繼承、多型特性
本網站聲明
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn
作者最新文章
最新問題
相關專題
更多>
熱門推薦
熱門教學
更多>
最新下載
更多>
網站特效
網站源碼
網站素材
前端模板