PHP的一個主要應用場合就是應用程序與數據庫打交道的應用場景,所以一個應用中會存在大量的數據庫操作,比如過數據庫句柄來連接數據庫這一行為,使用單例模式可以避免大量的new操作,因為每一次new操作都會消耗內存資源和系統資源。
【單例模式的優點】
1、對唯一實例的受控訪問
2、縮小命名空間 單例模式是對全局變量的一種改進。它避免了那些存儲唯一實例的全局變量污染命名空間
3、允許對操作和表示的精華 單例類可以有子類。而且用這個擴展類的實例來配置一個應用是很容易的。你可以用你所需要的類的實例在運行時刻配置應用。
4、允許可變數目的實例(多例模式)
5、比類操作更靈活
【單例模式適用場景】
1、當類只能有一個實例而且客戶可以從一個眾所周知的訪問點訪問它時
2、當這個唯一實例應該是通過子類化可擴展的。並且用戶應該無需更改代碼就能使用一個擴展的實例時。
【單例模式與其它模式】
工廠方法模式(factory method模式):單例模式使用工廠模式來提供自己的實例。
抽象工廠模式(abstract factory模式):抽象工廠模式可以使用單例模式,將具體工廠類設計成單例類。
建造者模式(Builder模式):建造模式可以將具體建造類設計成單例模式
3.單例模式實例
3.1 test.php
SPAN style="FONT-SIZE: 14px"><?php class Test{ public $service; //靜態成品變量 保存全局實例 private static $instance = null; //用mysqli連接數據庫 private static $SDB_USER = "test"; private static $SDB_DBNAME="test"; private static $SDB_HOST = 'localhost'; private static $SDB_PASS = 'ddddYQ3ddddUxEY'; //私有化構造函數,防止外界實例化對象 private function __construct() { $this->service = new mysqli(self::$SDB_HOST, self::$SDB_USER, self::$SDB_PASS, self::$SDB_DBNAME); } //私有化克隆函數,防止外界克隆對象 private function __clone(){ } //靜態方法, 單例統一訪問入口 public static function getInstance() { if (!isset(self::$instance) || is_null(self::$instance)) { self::$instance = new Test(); } return self::$instance; } //測試方法: 打印hello,world public function sayHello() { echo 'hello,world'; } } </SPAN> <?php class Test{ public $service; //靜態成品變量 保存全局實例 private static $instance = null; //用mysqli連接數據庫 private static $SDB_USER = "test"; private static $SDB_DBNAME="test"; private static $SDB_HOST = 'localhost'; private static $SDB_PASS = 'ddddYQ3ddddUxEY'; //私有化構造函數,防止外界實例化對象 private function __construct() { $this->service = new mysqli(self::$SDB_HOST, self::$SDB_USER, self::$SDB_PASS, self::$SDB_DBNAME); } //私有化克隆函數,防止外界克隆對象 private function __clone(){ } //靜態方法, 單例統一訪問入口 public static function getInstance() { if (!isset(self::$instance) || is_null(self::$instance)) { self::$instance = new Test(); } return self::$instance; } //測試方法: 打印hello,world public function sayHello() { echo 'hello,world'; } }
3.2 data.php
SPAN style="FONT-SIZE: 14px"><?php require_once('test.php'); class TestObject { protected $test; function __construct($id=null) { $this->test = Test::getInstance(); $this->test->sayHello(); } } $obj = new TestObject();</SPAN> <?php require_once('test.php'); class TestObject { protected $test; function __construct($id=null) { $this->test = Test::getInstance(); $this->test->sayHello(); } }
$obj = new TestObject();
運行data.php,結果:
4.PHP單例模式實現的核心要點有如下三條:
1. 需要一個保存類的唯一實例的靜態成員變量(通常為$instance私有變量)
2. 構造函數和克隆函數必須聲明為私有的,這是為了防止外部程序new類從而失去單例模式的意義
3. 必須提供一個訪問這個實例的公共的靜態方法(通常為getInstance方法),從而返回唯一實例的一個引用
5.PHP單例模式的缺點
眾所周知,PHP語言是一種解釋型的腳本語言,這種運行機制使得每個PHP頁面被解釋執行後,所有的相關資源都會被回收。也就是說,PHP在語言級別上沒有辦法讓某個對象常駐內存,這和asp.net、Java等編譯型是不同的,比如在Java中單例會一直存在於整個應用程序的生命周期裡,變量是跨頁面級的,真正可以做到這個實例在應用程序生命周期中的唯一性。然而在PHP中,所有的變量無論是全局變量還是類的靜態成員,都是頁面級的,每次頁面被執行時,都會重新建立新的對象,都會在頁面執行完畢後被清空,這樣似乎PHP單例模式就沒有什麼意義了,所以PHP單例模式我覺得只是針對單次頁面級請求時出現多個應用場景並需要共享同一對象資源時是非常有意義的。