一、什麼是單例模式?
1、意義
作為物件的建立模式,單例模式確保某一個類別只有一個實例,並且自行實例化並向整個系統全域提供這個實例。它不會建立實例副本,而是會向單例類別內部儲存的實例傳回一個參考。
2、單例模式的三個要點:
(1).需要一個保存類別的唯一實例的靜態成員變數:
private static $_instance;
(2). 建構函數與複製函數必須宣告為私有的,並防止外部程式new類別而失去單一範例模式的意義:
private function __construct() { $this->_db = pg_connect('xxxx'); } private function __clone() { }//覆盖__clone()方法,禁止克隆
(3). 必須提供一個存取這個實例的公共的靜態方法(通常為getInstance方法),從而傳回唯一實例的一個引用
public static function getInstance() { if(! (self::$_instance instanceof self) ) { self::$_instance = new self(); } return self::$_instance; }
二、為什麼要使用單例模式?
多數人都是從單例模式的字面上的意思來理解它的用途, 認為這是對系統資源的節省, 可以避免重複實例化, 是一種"計劃生育". 而PHP每次執行完頁面都是會從內存中清理掉所有的資源. 因而PHP中的單例實際每次運行都是需要重新實例化的, 這樣就失去了單例重複實例化的意義了. 單單從這方面來說, PHP的單例的確有點讓各位失望. 但是單例僅僅只有這個功能和應用嗎? 答案是否定的,我們一起來看看。
php的應用主要在於資料庫應用, 所以一個應用程式中會存在大量的資料庫操作, 在使用物件導向的方式開發時(廢話), 如果使用單例模式, 則可以避免大量的new 操作消耗的資源。
如果系統中需要有一個類別來全域控制某些設定資訊, 那麼使用單例模式可以很方便的實作. 這個可以參考zend Framework的FrontController部分。
在一次頁面請求中, 便於進行調試, 因為所有的代碼(例如數據庫操作類db)都集中在一個類中, 我們可以在類中設置鉤子, 輸出日誌,從而避免到處var_dump, echo。 1.PHP缺點:
PHP語言是一種解釋型的腳本語言,這種運作機制使得每個PHP頁面被解釋執行後,所有的相關資源都會被回收。也就是說,PHP在語言層級上沒有辦法讓某個物件常駐內存,這和asp.net、Java等編譯型是不同的,例如在Java中單例會一直存在於整個應用程式的生命週期裡,變數是跨頁面層級的,真正可以做到這個實例在應用程式生命週期中的唯一性。然而在PHP中,所有的變數無論是全域變數或類別的靜態成員,都是頁面層級的,每次頁面被執行時,都會重新建立新的對象,都會在頁面執行完畢後被清空,這樣似乎PHP單例模式就沒有什麼意義了,所以PHP單例模式我覺得只是針對單次頁面級請求時出現多個應用場景並需要共享同一對象資源時是非常有意義的。
2、單例模式在PHP中的應用場合:
(1)、應用程式與資料庫互動
一個應用程式中會存在大量的資料庫操作,例如過資料庫句柄來連接資料庫這一行為,使用單例模式可以避免大量的new操作,因為每一次new操作都會消耗記憶體資源和系統資源。
(2)、控製配置資訊
如果系統中需要有一個類別來全域控制某些設定資訊, 那麼使用單例模式可以很方便的實作.
#三、如何實現單例模式?
1、普通的資料庫存取範例:
<?php ...... //初始化一个数据库句柄 $db = new DB(...); //添加用户信息 $db->addUserInfo(...); ...... //在函数中访问数据库,查找用户信息 function getUserInfo() { $db = new DB(...);//再次new 数据库类,和数据库建立连接 $db = query(....);//根据查询语句访问数据库 } ?> 登入後複製 |
2、应用单例模式对数据库进行操作:
<?php class DB { private $_db; private static $_instance; private function __construct(...) { $this->_db = pg_connect(...);//postgrsql } private function __clone() {}; //覆盖__clone()方法,禁止克隆 public static function getInstance() { if(! (self::$_instance instanceof self) ) { self::$_instance = new self(); } return self::$_instance; } public function addUserInfo(...) { } public function getUserInfo(...) { } } //test $db = DB::getInstance(); $db->addUserInfo(...); $db->getUserInfo(...); ?>
下面的代码是PDO操作数据库类的一个封装,采用了单例模式:
/** * MyPDO */ class MyPDO { protected static $_instance = null; protected $dbName = ''; protected $dsn; protected $dbh;
/** * 构造 * * @return MyPDO */ private function __construct($dbHost, $dbUser, $dbPasswd, $dbName, $dbCharset) { try { $this->dsn = 'mysql:host='.$dbHost.';dbname='.$dbName; $this->dbh = new PDO($this->dsn, $dbUser, $dbPasswd); $this->dbh->exec('SET character_set_connection='.$dbCharset.', character_set_results='.$dbCharset.', character_set_client=binary'); } catch (PDOException $e) { $this->outputError($e->getMessage()); } }
/** * 防止克隆 * */ private function __clone() {}
/** * Singleton instance * * @return Object */ public static function getInstance($dbHost, $dbUser, $dbPasswd, $dbName, $dbCharset) { if (self::$_instance === null) { self::$_instance = new self($dbHost, $dbUser, $dbPasswd, $dbName, $dbCharset); } return self::$_instance; }
/** * Query 查询 * * @param String $strSql SQL语句 * @param String $queryMode 查詢方式(全部或行) * @param Boolean ## 公共函數查詢($strSql, $queryMode ='All', $debug = false) { # strSql); $recordset = $this->dbh->query($strSql);# { $recordset->setFetchMode(PDO::FETCH_ASSOC); $result = $recordset->fetchAll (); } elseif ($queryMode == 'Row') { } # } else { $result = null;# ## }
# /** * Update 更新 * * @param String $table # * @param String $where 條件 * @param Boolean $debug */ 公用函數 update($table, $arrayDataValue, $where = '', $debug = false) ## #$ this->checkFields($table, $arrayDataValue); if ($where) { tags.php/foreach/\"" target="\"_blank\"">foreach; ($arrayDataValue as $key => $value) {## $ strSql = substr($strSql, 1); 更新`$table` SET $strSql WHERE $where」; } else { array_keys($arrayDataValue))."`) VALUES ('".implode("','",$arrayDataValue)."')"; }## > == true) $this->debug($strSql); $result = $this->dbh->exec($strSql);# return $result; } # /** * Insert 插入 * * @param String $table # * @param Boolean $debug # * @return Int # */ public function insert($table, $arrayDataValue, $debug = false) { ($table, $arrayDataValue); $strSql = "INSERT INTO `$table` (`".implode('`,`', array_keys($arrayDataValue))."`) VALUES (' " .implode("','", $arrayDataValue)."')"; if ($debug === true) $ result = $this->dbh->exec($strSql); $this->getPDOError(); ## /** * Replace 覆寫方式插入 # * * @param String $table 表名 * @param Boolean $debug * @return Int # */ # 公用函數取代($table,$arrayDataValue,$debug = false) # # ## $this->checkFields($table, $arrayDataValue); $strSql = "替換為`$table`(`".implode('`,`', array_keys($ arrayDataValue))."` ) VALUES ('".implode("','", $arrayDataValue)."')"; if ($debug === true) $$0# $result = $this->dbh->exec($strSql); $this->getPDOError( 如果如果如果如果; } /** * Delete 刪除 * * @param String * @param Boolean $debug * @return Int */ 公用函數刪除($table, $where ='', $debug = false) { if ($where == '') { } else { $strSql = "DELETE FROM `$table` WHERE $where";); $result = $this->dbh->exec($strSql); return $result; } }
/** # * execSql 執行語句 # * execSql 執行語句# * @param String $strSql * @param Boolean $debug Sql($ strSql, $debug = false) { if ($debug === ->dbh->exec($strSql); $this->getPDOError(); # /** * 取得欄位最大值 * * @param string $table ## * @param string $where 條件 */# 公用函數getMaxValue($table, $field_name, $where ='', $debug = false)# { $strSql = "SELECT MAX(".$field_name.") AS MAX_VALUE FROM $table"; here "; if ($debug === true) $this->debug($strSql); ## $maxValue = $arrTemp["MAX_VALUE"]; if ($max ==) $maxValue = 0; } 返回$maxValue; }# ($table, $field_name, $where = '', $debug = false) { # if ($where != '') $strSql .= " WHERE $where"; # $arrTemp = $this->query($strSql, 'Row'); return ## /** * 取得指定列的數量 * * @param string $ @param string $where * @param bool $debug * @return int*/ 公用函數getTableEngine($dbName, $tableName) { ## $strSql = 「顯示表狀態來自於顯示表狀態來自於「顯示表狀態$dbName WHERE Name='”。$tableName。“'”;$arrayTableInfo = $this->query($strSql); $this-) # } /** * beginTransaction 事務開始 */ 私有函數beginTransaction( $this->dbh->beginTransaction();## }
## /** * commit 事務提交 */ ## # 私有函數提交()# 私有函數提交()# 私有函數提交()# 私有函數提交()# 私有函數提交()# 私有函數提交() { $this->dbh->commit();## } # } 私有函數 rollback() { $this->dbh->rollback(); # /** * rollback 事務回溯 */ # 公用函數 execTransaction($arraySql) {## ## this->beginTransaction(); foreach ($arraySql as $strSql) { if # } if ($retval == 0) { } else { $this->commit(); ## /** * transaction 透過事務處理多條SQL語句 * 調用前需透過getTableEngine判斷表引擎是否支援事務## ## #para*#para> $arraySql * @return Boolean */ {## $fields = $this-# $fields = $this-> ;getFiel#($); ## foreach ($arrayFields as $key =>; $value) { if (!in_array($key, $fields)) { ); } } # } 私有函數 getFields($table) ## { $fields = $table 中的欄位"); $this->getPDOError(); $ recordset->fetchAll(); foreach ($result as $rows) {# } return $fields; } /{ if ($this->dbh->errorCode() != '00000') {##o##11005 (); $this->outputError($arrayError[2]); } }
/** * getPDOError 擷取PDO錯誤訊息 */ 。 }
/** * 調試 * * @param 混合$debuginfo #111 */ 私有函數outputError($strErrMsg Exception('MySQL 錯誤: '.$strErrMsg); ## } # /** * 輸出錯誤訊息## * * @param String $strErrMsg # /** * destruct 關閉資料庫連線
{ $this->dbh = null; } }##gt;#? #
|
以上是PHP單例模式的優點分析的詳細內容。更多資訊請關注PHP中文網其他相關文章!