PHP單例模式應用詳解

原文地址:http://www.jb51.net/article/37742.htm

單例模式的要點有三個:

一是某個類只能有一個實例;
二是它必須自行創建這個實例;
三是它必須自行向整個系統提供這個實例。
複製代碼代碼如下:

<?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單例模式我覺得只是針對單次頁面級請求時出現多個應用場景並需要共享同一對象資源時是非常有意義的。
發佈了31 篇原創文章 · 獲贊 3 · 訪問量 14萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章