PHP中」單例模式「例項講解

2021-09-08 08:49:50 字數 3013 閱讀 8632

假設我們需要寫乙個類用來運算元據庫,並同時滿足以下要求:

①sqlhelper類只能有乙個例項(不能多)

②sqlhelper類必須能夠自行建立這個例項

③必須自行向整個系統提供這個例項,換句話說:多個物件共享一塊記憶體區域,比如,物件a設定了某些屬性值,則物件b,c也可以訪問這些屬性值(結尾的例子很好的說明了這個問題)

列印:fatal error: call to private sqlhelper::__construct() from invalid context

20 ?>

以上的sqlhelper類是無法從自身的類外部建立例項的,因為我們將建構函式設為了private,所以通過new sqlhelper()是無法從類外部使用私有的建構函式的,如果強制使用,將會報如下錯誤:

fatal error: call to private sqlhelper::__construct() from invalid context

嚴重錯誤:從上下文中呼叫了乙個私有的建構函式sqlhelper::__construct()

按照已往的思維邏輯,例項化乙個類都是直接在類外部使用new操作符的,但是既然這裡講建構函式設為private了,我們知道,私有的成員屬性或函式只能在類的內部被訪問,所以我們可以通過在類sqlhelper內部再建立乙個函式(比如:getinstance()),而且必須是public的,getinstance()函式中主要進行的是例項化sqlhelper類

比如:

1

<?php

2class

sqlhelper8//

......省略9}

10 ?>

但是問題出現了,

①我們在呼叫getinstance()之前沒有例項化sqlhelper物件,所以也就無法通過物件的方式來呼叫getinstance()函式了,

②既然在呼叫getinstance的時候還未例項化出物件,所以在getinstance函式中使用$this肯定也會報錯(fatal error: using $this when not in object context)

那如何解決呢?

解決途徑:我們可以講getinstance()方法設為靜態的,根據靜態的定義,她只能被類而不是物件呼叫,將$_instance也設為靜態的即可。所以這個方法正好符合我們的口味。

所以我們進一步將**修改如下:

1

<?php

2class

sqlhelper 7//

......省略

8public

static

function

getinstance()

13return self::$_instance;14

}15//......省略16}

17$sqlhelper=sqlhelper::getinstance();//

列印:建構函式被呼叫

18 ?>

通過在getinstance函式中對當前記憶體中有誤存在當類類的乙個例項進行判斷,如果沒有則例項化,並返回物件控制代碼,如果有則直接返回該物件控制代碼

至此,完整**如下所示:

1

<?php

2class

sqlhelper8//

getinstance()方法必須設定為公有的,必須呼叫此方法

9public

static

function

getinstance()

15return self::$_instance;16

}17public

function

getdbname()

20public

function setdbname($dbname)23

}24//$sqlhelper=new sqlhelper();//列印:fatal error: call to private sqlhelper::__construct() from invalid context

25$a=sqlhelper::getinstance();

26$a->setdbname('資料庫名');

27$a->getdbname();

28//

unset($a);//移除引用

29$b=sqlhelper::getinstance();

30$b->getdbname();

31$c=sqlhelper::getinstance();

32$c->getdbname();

3334 ?>

以上**的執行結果:

資料庫名//$a->getdbname();

資料庫名//$b->getdbname();

資料庫名//$c->getdbname();

也就是說,物件a,b,c實際上都是使用同乙個物件例項,訪問的都是同一塊記憶體區域

所以,即使unset($a),物件b和c還是照樣能夠通過getdbname()方法輸出「資料庫名」的

unset($a)實際上只是將物件a與某塊記憶體位址(該物件的例項所在的位址)之間的****斷開而已,跟物件b和物件c無關,可以用用一張圖表示如下

原創文章:marcofly

php清空單例屬性 php的單例模式講解

場景 class mysql my1 new mysql my2 new mysql my3 new mysql 每new一次,連線一次資料庫 同時,多了乙個物件,增大的開銷 另一種場景 購物車 如果我開啟多個頁面,每個頁面例項了多個購物車 那麼下的訂單,可能會被裝在不同的購物車裡,出現錯誤.所以,...

php單例模式的例項

class config1 class config 轉殖方法私有化 禁止從外部轉殖物件 private function clone 因為用靜態屬性返回類例項,而只能在靜態方法使用靜態屬性 所以必須建立乙個靜態方法來生成當前類的唯一例項 public static function getinst...

單例模式講解

單例模式被當作職責模式,他用來在應用程式中建立乙個單一的功能訪問點。它將建立物件的控制權委託到一 個單一的訪問點上。在任何時候,應用程式中都只會有這個類僅有的乙個例項存在。這可以防止我們去開啟資料庫的多個連線或者不必要得使用多餘的系統資源。在 更加複雜的系統中,使用單例模式在維持應用程式狀態的同步方...