單例模式確保某個類只有一個實例,而且自行實例化并向整個系統提供這個實例。
單例模式是一種常見的設計模式,在計算機系統中,線程池、緩存、日志對象、對話框、打印機、數據庫操作、顯卡的驅動程序常被設計成單例。
單例模式有以下3個特點:
1.只能有一個實例。
2.必須自行創建這個實例。
3.必須給其他對象提供這一實例。
那么為什么要使用PHP單例模式?
PHP一個主要應用場合就是應用程序與數據庫打交道的場景,在一個應用中會存在大量的數據庫操作,針對數據庫句柄連接數據庫的行為,使用單例模式可以避免大量的new操作。因為每一次new操作都會消耗系統和內存的資源。
然而,PHP在語言級別上沒有辦法讓某個對象常駐內存。在PHP中,所有的變量都是頁面級的,無論是全局變量,不過,在實際應用中同一個頁面中可能會存在多個業務邏輯,這時單例模式就起到了很重要的作用,有效的避免了重復 ,雖然有時候會有些雞肋。
在不使用單例的情況下我們在一個類里面操作數據庫可能是這樣的:
<?php
function updateUserInfo(){
$db = new DB(...);
$db->query();
}
function getOneUser($id){
//多次初始化數據庫連接
$db = new DB(...);
$user = $db->query($id);
updateUserInfo($id);
}
顯然連接數據庫的操作在連接同一個數據庫的情況下是適用于所有的,所以在這種情況下單例能大大減少不必要的資源消耗,大多數php框架數據庫連接都是采用單例模式,以下是使用單例的做法:
<?php
class DB{
//私有化的全局實例
static private $_instance = NULL;
/**
* 私有化構造函數,防止外界實例化對象
*/
private function __construct() {
\\連接數據庫
}
/**
* 私有化克隆函數,防止外界克隆對象
*/
private function __clone(){}
/**
* 靜態方法, 單例統一訪問入口,如果存在實例返回該實例,否則創建新實例
* @return object 返回對象的唯一實例
*/
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.需要一個保存類的唯一實例的靜態成員變量(通常為$_instance私有變量)
2.構造函數和克隆函數必須聲明為私有的,這是為了防止外部程序new類從而失去單例模式的意義
3.必須提供一個訪問這個實例的公共的靜態方法(通常為getInstance方法),從而返回唯一實例的一個引用
PHP單例模式的缺點
眾所周知,PHP語言是一種解釋型的腳本語言,這種運行機制使得每個PHP頁面被解釋執行后,所有的相關資源都會被回收。也就是說,PHP在語言級別上沒有辦法讓某個對象常駐內存,這和asp.net、Java等編譯型是不同的,比如在Java中單例會一直存在于整個應用程序的生命周期里,變量是跨頁面級的,真正可以做到這個實例在應用程序生命周期中的唯一性。然而在PHP中,所有的變量無論是全局變量還是類的靜態成員,都是頁面級的,每次頁面被執行時,都會重新建立新的對象,都會在頁面執行完畢后被清空,這樣似乎PHP單例模式就沒有什么意義了,所以PHP單例模式我覺得只是針對單次頁面級請求時出現多個應用場景并需要共享同一對象資源時是非常有意義的。