單例模式(Singleton Pattern 單件模式或單元素模式)
單例模式確保某個類只有一個實例,而且自行實例化並向整個系統提供這個實例。
單例模式是一種常見的設計模式,在計算機系統中,線程池、緩存、日志對象、對話框、打印機、數據庫操作、顯卡的驅動程序常被設計成單例。
單例模式分3種:懶漢式單例、餓漢式單例、登記式單例。
單例模式有以下3個特點:
1.只能有一個實例。
2.必須自行創建這個實例。
3.必須給其他對象提供這一實例。
那么為什么要使用PHP單例模式?
PHP一個主要應用場合就是應用程序與數據庫打交道的場景,在一個應用中會存在大量的數據庫操作,針對數據庫句柄連接數據庫的行為,使用單例模式可以避免大量的new操作。因為每一次new操作都會消耗系統和內存的資源。
在以往的項目開發中,沒使用單例模式前的情況如下:
//初始化一個數據庫句柄 $db = new DB(...); //比如有個應用場景是添加一條用戶信息 $db->addUserInfo(); ...... //然而我們要在另一地方使用這個用戶信息,這時要用到數據庫句柄資源,可能會這么做 ...... function test() { $db = new DB(...); $db->getUserInfo(); ...... 有些朋友也許會說,可以直接使用global關鍵字! global $db; ......
的確global可以解決問題,也起到單例模式的作用,但在OOP中,我們拒絕這種編碼。因為global存在安全隱患(全局變量不受保護的本質)。
全局變量是面向對象程序員遇到的引發BUG的主要原因之一。這是因為全局變量將類捆綁於特定的環境,破壞了封裝。如果新的應用程序無法保證一開始就定義了相同的全局變量,那么一個依賴於全局變量的類就無法從一個應用程序中提取出來並應用到新應用程序中。
確切的講,單例模式恰恰是對全局變量的一種改進,避免那些存儲唯一實例的全局變量污染命名空間。你無法用錯誤類型的數據覆寫一個單例。這種保護在不支持命名空間的PHP版本里尤其重要。因為在PHP中命名沖突會在編譯時被捕獲,並使腳本停止運行。
PHP單例模式實例:
先看圖:
上面的對象圖中,有一個“單例對象”,而“客戶甲”、“客戶乙”和“客戶丙”是單例對象的三個客戶對象。可以看到,所有的客戶對象共享一個單例對象。而且從單例對象到自身的連接線可以看出,單例對象持有對自己的引用。
<?php class User { //靜態變量保存全局實例 private static $_instance = null; //私有構造函數,防止外界實例化對象 private function __construct() { } //私有克隆函數,防止外辦克隆對象 private function __clone() { } //靜態方法,單例統一訪問入口 static public function getInstance() { if (is_null ( self::$_instance ) || isset ( self::$_instance )) { self::$_instance = new self (); } return self::$_instance; } public function getName() { echo 'hello world!'; } } ?>
單例模式的優缺點:
優點:
1. 改進系統的設計
2. 是對全局變量的一種改進
缺點:
1. 難於調試
2. 隱藏的依賴關系
3. 無法用錯誤類型的數據覆寫一個單例