單例模式確保某個(gè)類只有一個(gè)實(shí)例则酝,而且自行實(shí)例化并向整個(gè)系統(tǒng)提供這個(gè)實(shí)例殉簸。
單例模式是一種常見的設(shè)計(jì)模式闰集,在計(jì)算機(jī)系統(tǒng)中,線程池般卑、緩存武鲁、日志對(duì)象、對(duì)話框蝠检、打印機(jī)沐鼠、數(shù)據(jù)庫操作、顯卡的驅(qū)動(dòng)程序常被設(shè)計(jì)成單例叹谁。
單例模式有以下3個(gè)特點(diǎn):
1.只能有一個(gè)實(shí)例饲梭。
2.必須自行創(chuàng)建這個(gè)實(shí)例。
3.必須給其他對(duì)象提供這一實(shí)例焰檩。
那么為什么要使用PHP單例模式憔涉?
PHP一個(gè)主要應(yīng)用場(chǎng)合就是應(yīng)用程序與數(shù)據(jù)庫打交道的場(chǎng)景,在一個(gè)應(yīng)用中會(huì)存在大量的數(shù)據(jù)庫操作析苫,針對(duì)數(shù)據(jù)庫句柄連接數(shù)據(jù)庫的行為兜叨,使用單例模式可以避免大量的new操作。因?yàn)槊恳淮蝞ew操作都會(huì)消耗系統(tǒng)和內(nèi)存的資源衩侥。
然而国旷,PHP在語言級(jí)別上沒有辦法讓某個(gè)對(duì)象常駐內(nèi)存。在PHP中茫死,所有的變量都是頁面級(jí)的议街,無論是全局變量,不過,在實(shí)際應(yīng)用中同一個(gè)頁面中可能會(huì)存在多個(gè)業(yè)務(wù)邏輯,這時(shí)單例模式就起到了很重要的作用,有效的避免了重復(fù) ,雖然有時(shí)候會(huì)有些雞肋璧榄。
在不使用單例的情況下我們?cè)谝粋€(gè)類里面操作數(shù)據(jù)庫可能是這樣的:
<?php
function updateUserInfo(){
$db = new DB(...);
$db->query();
}
function getOneUser($id){
//多次初始化數(shù)據(jù)庫連接
$db = new DB(...);
$user = $db->query($id);
updateUserInfo($id);
}
顯然連接數(shù)據(jù)庫的操作在連接同一個(gè)數(shù)據(jù)庫的情況下是適用于所有的特漩,所以在這種情況下單例能大大減少不必要的資源消耗,大多數(shù)php框架數(shù)據(jù)庫連接都是采用單例模式骨杂,以下是使用單例的做法:
<?php
class DB{
//私有化的全局實(shí)例
static private $_instance = NULL;
/**
* 私有化構(gòu)造函數(shù)涂身,防止外界實(shí)例化對(duì)象
*/
private function __construct() {
\\連接數(shù)據(jù)庫
}
/**
* 私有化克隆函數(shù),防止外界克隆對(duì)象
*/
private function __clone(){}
/**
* 靜態(tài)方法, 單例統(tǒng)一訪問入口搓蚪,如果存在實(shí)例返回該實(shí)例蛤售,否則創(chuàng)建新實(shí)例
* @return object 返回對(duì)象的唯一實(shí)例
*/
static public function getInstance() {
if (is_null(self::$_instance) || !isset(self::$_instance)) {
self::$_instance = new self();
}
return self::$_instance;
}
//測(cè)試單例
public function getName() {
echo 'hello world!';
}
}
所以總結(jié)如下
1.需要一個(gè)保存類的唯一實(shí)例的靜態(tài)成員變量(通常為$_instance私有變量)
2.構(gòu)造函數(shù)和克隆函數(shù)必須聲明為私有的,這是為了防止外部程序new類從而失去單例模式的意義
3.必須提供一個(gè)訪問這個(gè)實(shí)例的公共的靜態(tài)方法(通常為getInstance方法)妒潭,從而返回唯一實(shí)例的一個(gè)引用
PHP單例模式的缺點(diǎn)
眾所周知悴能,PHP語言是一種解釋型的腳本語言,這種運(yùn)行機(jī)制使得每個(gè)PHP頁面被解釋執(zhí)行后雳灾,所有的相關(guān)資源都會(huì)被回收漠酿。也就是說,PHP在語言級(jí)別上沒有辦法讓某個(gè)對(duì)象常駐內(nèi)存谎亩,這和asp.net炒嘲、Java等編譯型是不同的宇姚,比如在Java中單例會(huì)一直存在于整個(gè)應(yīng)用程序的生命周期里,變量是跨頁面級(jí)的夫凸,真正可以做到這個(gè)實(shí)例在應(yīng)用程序生命周期中的唯一性浑劳。然而在PHP中,所有的變量無論是全局變量還是類的靜態(tài)成員夭拌,都是頁面級(jí)的魔熏,每次頁面被執(zhí)行時(shí),都會(huì)重新建立新的對(duì)象鸽扁,都會(huì)在頁面執(zhí)行完畢后被清空蒜绽,這樣似乎PHP單例模式就沒有什么意義了,所以PHP單例模式我覺得只是針對(duì)單次頁面級(jí)請(qǐng)求時(shí)出現(xiàn)多個(gè)應(yīng)用場(chǎng)景并需要共享同一對(duì)象資源時(shí)是非常有意義的献烦。