單例模式的要點有三個:
一是某個類只能有一個執行個體;
二是它必須自行建立這個執行個體;
三是它必須自行向整個系統提供這個執行個體。
<?php
/* 單例模式舉例,其要點如下:
*
* 1. $_instance 必須聲明為靜態私人變數
* 2. 建構函式和複製函數必須聲明為私人的,這是為了防止外部程式 new 類從而失去單例模式的意義
* 3. getInstance()方法必須聲明為公有的,必須調用此方法以返回唯一執行個體的一個引用
* 4. ::操作符只能訪問靜態變數或靜態函數
* 5. PHP的單例模式是相對而言的,因為PHP的解釋運行機制使得每個PHP頁面被解釋執行後,所有的相關資源都會被回收。
* 也就是說,PHP在語言層級上沒有辦法讓某個對象常駐記憶體。在PHP中,所有的變數都是頁面級的,無論是全域變數,
* 還是類的靜態成員,都會在頁面執行完畢後被清空,結果會重建立立新的對象,這樣也就完全失去了Singleton的意義。
* 不過,在實際應用中同一個頁面中可能會存在多個商務邏輯,這時單例模式就起到了很重要的作用,有效避免了重複
* new 對象(注: new 對象會消耗記憶體資源)這麼一個行為,所以我們說PHP的單例模式是相對而言的
*
*/
class People
{
static private $_instance = NULL;
public $height = '';
public $age = '';
private function __construct()
{
$this->height = '185';
$this->age = 25;
}
private function __clone()
{
//do something
}
static public function getInstance()
{
if(!self::$_instance instanceof self)
{
//echo 'lgh-big';
self::$_instance = new self;
}
else
{
//for testing only
//echo 'gdc-xiaoairener';
}
return self::$_instance;
}
public function getHeight()
{
echo $this->height;
}
public function getAge()
{
echo $this->age;
}
}
function testInstance()
{
People::getInstance()->getAge();
}
//begin to use the class
$lgh = People::getInstance();
$lgh->getHeight();
echo '<br />';
testInstance();
?>
優點:單例模式可以避免大量的new操作,因為每一次new操作都會消耗記憶體資源和系統資源
缺點:在PHP中,所有的變數無論是全域變數還是類的靜態成員,都是 頁面級的,每次頁面被執行時,都會重建立立新的對象,都會在頁面執行完畢後被清空,這樣似乎PHP單例模式就沒有什麼意義了,所以PHP單例模式我覺得只 是針對單次頁面級請求時出現多個應用情境並需要共用同一對象資源時是非常有意義的。
Why–為什麼要使用PHP單例模式?
PHP的一個主要應用場合就是應用程式與資料庫打交道的應用情境,所以一個應用中會存在大量的資料庫操作,比如過資料庫控制代碼來串連資料庫這一行為,使用單例模式可以避免大量的new操作,因為每一次new操作都會消耗記憶體資源和系統資源。
還是有些抽象,給出程式碼片段。
使用傳統方式編碼
<?php......//初始化一個資料庫控制代碼$db = new DB(...);//比如有個應用情境是添加一條使用者資訊:$db->addUserInfo();......//然而我們在另外一個地方可能要尋找使用者的資訊,這個情景出現在一個函數中,這時要用到資料庫控制代碼資源,我們可能需要這麼去做......function test(){......//這時我們不得不重新初始化一個資料庫控制代碼,試想多個應用情境下,這樣的代碼是多麼可怕啊?!$db = new DB(...);$db->getUserInfo();......//有些朋友或許會說,我也可以不這樣做啊,我直接利用global關鍵字不就可以了嗎?的確,global可以解決問題,也起到了單例模式的作用,但是OOP中,我們拒絕這樣來編寫代碼,因為global存在安全隱患,請參考相關書籍,同時單例模式恰恰是對全域變數的一種改進,避免了那些儲存唯一執行個體的全域變數汙染命名空間global $db; //OOP中,我們不提倡這樣編寫代碼......}
使用單例模式編碼
<?php......//所有的應用情景只有一個資料庫控制代碼資源,嘿嘿,效率老高了,//資源也大大的得到節省,代碼簡潔明了:)DB::getInstance()->addUserInfo();DB::getInstance()->getUserInfo();......
How–如何來編寫PHP單例模式?
在瞭解了單例模式的應用情境之後,下面我們通過編寫單例模式的具體實現代碼來掌握PHP單例模式的核心要點,代碼如下:
<?php/** * PHP單例模式示範舉例* @author guohua.li * @modify 2010-07-11* @website http://blog.163.com/lgh_2002/*/class User{ /** * 靜態成品變數 儲存全域執行個體 * @access private */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 liguohua!'; }}
從以上代碼中,我們總結出PHP單例模式實現的核心要點有如下三條:
1. 需要一個儲存類的唯一執行個體的靜態成員變數(通常為$_instance私人變數)
2. 建構函式和複製函數必須聲明為私人的,這是為了防止外部程式new類從而失去單例模式的意義
3. 必須提供一個訪問這個執行個體的公用的靜態方法(通常為getInstance方法),從而返回唯一執行個體的一個引用
PHP單例模式的缺點
眾所周知,PHP語言是一種解釋型的指令碼語言,這種運行機制使得每個PHP頁面被解釋執行後,所有的相關資源都會被回收。也就是說,PHP在語言層級上沒有辦法讓某個對象常駐記憶體,這和asp.net、Java等編譯型是不同的,比如在Java中單例會一直存在於整個應用程式的生命週期裡,變數是跨頁面級的,真正可以做到這個執行個體在應用程式生命週期中的唯一性。然而在PHP中,所有的變數無論是全域變數還是類的靜態成員,都是頁面級的,每次頁面被執行時,都會重建立立新的對象,都會在頁面執行完畢後被清空,這樣似乎PHP單例模式就沒有什麼意義了,所以PHP單例模式我覺得只是針對單次頁面級請求時出現多個應用情境並需要共用同一對象資源時是非常有意義的。
作者:李國華 E-mail:jiaoshiok@gmail.com lgh_2002@163.com
LAMP兄弟連資訊,轉載請註明出處!