一、什麼是單例模式?
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; }
二、為什麼要使用單例模式?
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操作數據庫類的一個封裝,采用了單例模式:
<?php /** * 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 查詢方式(All or Row) * @param Boolean $debug * @return Array */ public function query($strSql, $queryMode = 'All', $debug = false) { if ($debug === true) $this->debug($strSql); $recordset = $this->dbh->query($strSql); $this->getPDOError(); if ($recordset) { $recordset->setFetchMode(PDO::FETCH_ASSOC); if ($queryMode == 'All') { $result = $recordset->fetchAll(); } elseif ($queryMode == 'Row') { $result = $recordset->fetch(); } } else { $result = null; } return $result; } /** * Update 更新 * * @param String $table 表名 * @param Array $arrayDataValue 字段與值 * @param String $where 條件 * @param Boolean $debug * @return Int */ public function update($table, $arrayDataValue, $where = '', $debug = false) { $this->checkFields($table, $arrayDataValue); if ($where) { $strSql = ''; foreach ($arrayDataValue as $key => $value) { $strSql .= ", `$key`='$value'"; } $strSql = substr($strSql, 1); $strSql = "UPDATE `$table` SET $strSql WHERE $where"; } else { $strSql = "REPLACE INTO `$table` (`".implode('`,`', array_keys($arrayDataValue))."`) VALUES ('".implode("','", $arrayDataValue)."')"; } if ($debug === true) $this->debug($strSql); $result = $this->dbh->exec($strSql); $this->getPDOError(); return $result; } /** * Insert 插入 * * @param String $table 表名 * @param Array $arrayDataValue 字段與值 * @param Boolean $debug * @return Int */ public function insert($table, $arrayDataValue, $debug = false) { $this->checkFields($table, $arrayDataValue); $strSql = "INSERT INTO `$table` (`".implode('`,`', array_keys($arrayDataValue))."`) VALUES ('".implode("','", $arrayDataValue)."')"; if ($debug === true) $this->debug($strSql); $result = $this->dbh->exec($strSql); $this->getPDOError(); return $result; } /** * Replace 覆蓋方式插入 * * @param String $table 表名 * @param Array $arrayDataValue 字段與值 * @param Boolean $debug * @return Int */ public function replace($table, $arrayDataValue, $debug = false) { $this->checkFields($table, $arrayDataValue); $strSql = "REPLACE INTO `$table`(`".implode('`,`', array_keys($arrayDataValue))."`) VALUES ('".implode("','", $arrayDataValue)."')"; if ($debug === true) $this->debug($strSql); $result = $this->dbh->exec($strSql); $this->getPDOError(); return $result; } /** * Delete 刪除 * * @param String $table 表名 * @param String $where 條件 * @param Boolean $debug * @return Int */ public function delete($table, $where = '', $debug = false) { if ($where == '') { $this->outputError("'WHERE' is Null"); } else { $strSql = "DELETE FROM `$table` WHERE $where"; if ($debug === true) $this->debug($strSql); $result = $this->dbh->exec($strSql); $this->getPDOError(); return $result; } } /** * execSql 執行SQL語句 * * @param String $strSql * @param Boolean $debug * @return Int */ public function execSql($strSql, $debug = false) { if ($debug === true) $this->debug($strSql); $result = $this->dbh->exec($strSql); $this->getPDOError(); return $result; } /** * 獲取字段最大值 * * @param string $table 表名 * @param string $field_name 字段名 * @param string $where 條件 */ public function getMaxValue($table, $field_name, $where = '', $debug = false) { $strSql = "SELECT MAX(".$field_name.") AS MAX_VALUE FROM $table"; if ($where != '') $strSql .= " WHERE $where"; if ($debug === true) $this->debug($strSql); $arrTemp = $this->query($strSql, 'Row'); $maxValue = $arrTemp["MAX_VALUE"]; if ($maxValue == "" || $maxValue == null) { $maxValue = 0; } return $maxValue; } /** * 獲取指定列的數量 * * @param string $table * @param string $field_name * @param string $where * @param bool $debug * @return int */ public function getCount($table, $field_name, $where = '', $debug = false) { $strSql = "SELECT COUNT($field_name) AS NUM FROM $table"; if ($where != '') $strSql .= " WHERE $where"; if ($debug === true) $this->debug($strSql); $arrTemp = $this->query($strSql, 'Row'); return $arrTemp['NUM']; } /** * 獲取表引擎 * * @param String $dbName 庫名 * @param String $tableName 表名 * @param Boolean $debug * @return String */ public function getTableEngine($dbName, $tableName) { $strSql = "SHOW TABLE STATUS FROM $dbName WHERE Name='".$tableName."'"; $arrayTableInfo = $this->query($strSql); $this->getPDOError(); return $arrayTableInfo[0]['Engine']; } /** * beginTransaction 事務開始 */ private function beginTransaction() { $this->dbh->beginTransaction(); } /** * commit 事務提交 */ private function commit() { $this->dbh->commit(); } /** * rollback 事務回滾 */ private function rollback() { $this->dbh->rollback(); } /** * transaction 通過事務處理多條SQL語句 * 調用前需通過getTableEngine判斷表引擎是否支持事務 * * @param array $arraySql * @return Boolean */ public function execTransaction($arraySql) { $retval = 1; $this->beginTransaction(); foreach ($arraySql as $strSql) { if ($this->execSql($strSql) == 0) $retval = 0; } if ($retval == 0) { $this->rollback(); return false; } else { $this->commit(); return true; } } /** * checkFields 檢查指定字段是否在指定數據表中存在 * * @param String $table * @param array $arrayField */ private function checkFields($table, $arrayFields) { $fields = $this->getFields($table); foreach ($arrayFields as $key => $value) { if (!in_array($key, $fields)) { $this->outputError("Unknown column `$key` in field list."); } } } /** * getFields 獲取指定數據表中的全部字段名 * * @param String $table 表名 * @return array */ private function getFields($table) { $fields = array(); $recordset = $this->dbh->query("SHOW COLUMNS FROM $table"); $this->getPDOError(); $recordset->setFetchMode(PDO::FETCH_ASSOC); $result = $recordset->fetchAll(); foreach ($result as $rows) { $fields[] = $rows['Field']; } return $fields; } /** * getPDOError 捕獲PDO錯誤信息 */ private function getPDOError() { if ($this->dbh->errorCode() != '00000') { $arrayError = $this->dbh->errorInfo(); $this->outputError($arrayError[2]); } } /** * debug * * @param mixed $debuginfo */ private function debug($debuginfo) { var_dump($debuginfo); exit(); } /** * 輸出錯誤信息 * * @param String $strErrMsg */ private function outputError($strErrMsg) { throw new Exception('MySQL Error: '.$strErrMsg); } /** * destruct 關閉數據庫連接 */ public function destruct() { $this->dbh = null; } } ?>
調用方法:
<?php require 'MyPDO.class.php'; $db = MyPDO::getInstance('localhost', 'root', '123456', 'test', 'utf8'); $db->query("select count(*) frome table"); $db->destruct(); ?>
以上就是本文的全部內容,希望對大家學習php程序設計有所幫助。