本文實(shí)例講述了PHP單例模式應(yīng)用。分享給大家供大家參考,具體如下:
以前剛開始工作的時(shí)候經(jīng)常連接數(shù)據(jù)庫,每次用到數(shù)據(jù)庫的時(shí)候就要用new進(jìn)行實(shí)例并連接一次,當(dāng)時(shí)因?yàn)檫B接數(shù)據(jù)庫的次數(shù)不是很頻繁,所以也沒什么。后來主管對我說我現(xiàn)在這樣每次都連接數(shù)據(jù)庫的如果數(shù)據(jù)讀取頻繁的話對數(shù)據(jù)庫和系統(tǒng)造成的壓力會很大,讓我想想辦法能不能就連接一次數(shù)據(jù)庫然后再次用到的時(shí)候就不用new一個新的連接了,當(dāng)時(shí)怎么也沒想到好的辦法,知道最近學(xué)到了單例模式才恍然大悟,當(dāng)時(shí)主管是引導(dǎo)我用單例模式的,只怪我以前對開發(fā)模式不懂。好了廢話少說,下面來看單例模式:
單例模式(職責(zé)模式):
簡單的說,一個對象(在學(xué)習(xí)設(shè)計(jì)模式之前,需要比較了解面向?qū)ο笏枷耄┲回?fù)責(zé)一個特定的任務(wù);
單例類:
1、構(gòu)造函數(shù)需要標(biāo)記為private
(訪問控制:防止外部代碼使用new操作符創(chuàng)建對象),單例類不能在其他類中實(shí)例化,只能被其自身實(shí)例化;
2、擁有一個保存類的實(shí)例的靜態(tài)成員變量
3、擁有一個訪問這個實(shí)例的公共的靜態(tài)方法(常用getInstance()
方法進(jìn)行實(shí)例化單例類,通過instanceof
操作符可以檢測到類是否已經(jīng)被實(shí)例化)
另外,需要創(chuàng)建__clone()
方法防止對象被復(fù)制(克隆)
為什么要使用PHP單例模式?
1、php的應(yīng)用主要在于數(shù)據(jù)庫應(yīng)用, 所以一個應(yīng)用中會存在大量的數(shù)據(jù)庫操作, 使用單例模式, 則可以避免大量的new
操作消耗的資源。
2、如果系統(tǒng)中需要有一個類來全局控制某些配置信息, 那么使用單例模式可以很方便的實(shí)現(xiàn). 這個可以參看ZF的FrontController部分。
3、在一次頁面請求中, 便于進(jìn)行調(diào)試, 因?yàn)樗械拇a(例如數(shù)據(jù)庫操作類db)都集中在一個類中, 我們可以在類中設(shè)置鉤子, 輸出日志,從而避免到處var_dump
, echo
。
代碼(官方文檔中的):
?php
class Singletons{
// 保存類實(shí)例在此屬性中
private static $instance;
// 構(gòu)造方法聲明為private,防止直接創(chuàng)建對象
private function __construct()
{
echo 'Iam constructed';
}
// singleton 方法
public static function singleton()
{
if (!isset(self::$instance)) {
$c = __CLASS__;
self::$instance =new$c;
}
return self::$instance;
}
// Example類中的普通方法
public function bark()
{
echo 'Woof!';
}
// 阻止用戶復(fù)制對象實(shí)例
public function __clone()
{
trigger_error('Clone is not allowed.',E_USER_ERROR);
}
}//endclass singletons
//這個寫法會出錯,因?yàn)闃?gòu)造方法被聲明為private
//$test= new Singletons();
// 下面將得到Example類的單例對象
$test= Singletons::singleton();
$test->bark();
// 復(fù)制對象將導(dǎo)致一個E_USER_ERROR.
$test_clone= clone $test;
?>
結(jié)果:
I am constructed! Woof!
Fatal error:
Clone is not allowed. in E:\APMServ5.2.6\www\htdocs\Lee\myprogram\other\class\singletons.phpon line 31
以下內(nèi)容源自網(wǎng)絡(luò)(可以參考學(xué)習(xí)一下):
單例模式的三個要點(diǎn):
(1). 需要一個保存類的唯一實(shí)例的靜態(tài)成員變量:
private static $_instance;
(2). 構(gòu)造函數(shù)和克隆函數(shù)必須聲明為私有的,防止外部程序new類從而失去單例模式的意義:
private function __construct()
{
$this->_db = pg_connect('xxxx');
}
private function __clone()
{
}//覆蓋__clone()方法,禁止克隆
(3). 必須提供一個訪問這個實(shí)例的公共的靜態(tài)方法(通常為getInstance
方法),從而返回唯一實(shí)例的一個引用
public static function getInstance()
{
if(! (self::$_instance instanceof self) )
{
self::$_instance = new self();
}
return self::$_instance;
}
二、為什么要使用單例模式?
1、PHP缺點(diǎn):
PHP語言是一種解釋型的腳本語言,這種運(yùn)行機(jī)制使得每個PHP頁面被解釋執(zhí)行后,所有的相關(guān)資源都會被回收。也就是說,PHP在語言級別上沒有辦法讓某個對象常駐內(nèi)存,這和asp.NET、Java等編譯型是不同的,比如在Java中單例會一直存在于整個應(yīng)用程序的生命周期里,變量是跨頁面級的,真正可以做到這個實(shí)例在應(yīng)用程序生命周期中的唯一性。然而在PHP中,所有的變量無論是全局變量還是類的靜態(tài)成員,都是頁面級的,每次頁面被執(zhí)行時(shí),都會重新建立新的對象,都會在頁面執(zhí)行完畢后被清空,這樣似乎PHP單例模式就沒有什么意義了,所以PHP單例模式我覺得只是針對單次頁面級請求時(shí)出現(xiàn)多個應(yīng)用場景并需要共享同一對象資源時(shí)是非常有意義的。
2、單例模式在PHP中的應(yīng)用場合:
(1)、應(yīng)用程序與數(shù)據(jù)庫交互
一個應(yīng)用中會存在大量的數(shù)據(jù)庫操作,比如過數(shù)據(jù)庫句柄來連接數(shù)據(jù)庫這一行為,使用單例模式可以避免大量的new操作,因?yàn)槊恳淮?code>new操作都會消耗內(nèi)存資源和系統(tǒng)資源。
(2)、控制配置信息
如果系統(tǒng)中需要有一個類來全局控制某些配置信息,那么使用單例模式可以很方便的實(shí)現(xiàn).
三、如何實(shí)現(xiàn)單例模式?
1、普通的數(shù)據(jù)庫訪問例子:
?php
......
//初始化一個數(shù)據(jù)庫句柄
$db = new DB(...);
//添加用戶信息
$db->addUserInfo(...);
......
//在函數(shù)中訪問數(shù)據(jù)庫,查找用戶信息
function getUserInfo()
{
$db = new DB(...);//再次new 數(shù)據(jù)庫類,和數(shù)據(jù)庫建立連接
$db = query(....);//根據(jù)查詢語句訪問數(shù)據(jù)庫
}
?>
2、應(yīng)用單例模式對數(shù)據(jù)庫進(jìn)行操作:
?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(...);
?>
3、深入理解
?php
class db {
public $conn;
public static $sql;
public static $instance=null;
private function __construct(){
require_once('db.config.php');
$this->conn = mysql_connect($db['host'],$db['user'],$db['password']);
if(!mysql_select_db($db['database'],$this->conn)){
echo "失敗";
};
mysql_query('set names utf8',$this->conn);
}
public static function getInstance(){
if(is_null(self::$instance)){
self::$instance = new db;
}
return self::$instance;
}
/**
* 查詢數(shù)據(jù)庫
*/
public function select($table,$condition=array(),$field = array()){
$where='';
if(!empty($condition)){
foreach($condition as $k=>$v){
$where.=$k."='".$v."' and ";
}
$where='where '.$where .'1=1';
}
$fieldstr = '';
if(!empty($field)){
foreach($field as $k=>$v){
$fieldstr.= $v.',';
}
$fieldstr = rtrim($fieldstr,',');
}else{
$fieldstr = '*';
}
self::$sql = "select {$fieldstr} from {$table} {$where}";
$result=mysql_query(self::$sql,$this->conn);
$resuleRow = array();
$i = 0;
while($row=mysql_fetch_assoc($result)){
foreach($row as $k=>$v){
$resuleRow[$i][$k] = $v;
}
$i++;
}
return $resuleRow;
}
/**
* 添加一條記錄
*/
public function insert($table,$data){
$values = '';
$datas = '';
foreach($data as $k=>$v){
$values.=$k.',';
$datas.="'$v'".',';
}
$values = rtrim($values,',');
$datas = rtrim($datas,',');
self::$sql = "INSERT INTO {$table} ({$values}) VALUES ({$datas})";
if(mysql_query(self::$sql)){
return mysql_insert_id();
}else{
return false;
};
}
/**
* 修改一條記錄
*/
public function update($table,$data,$condition=array()){
$where='';
if(!empty($condition)){
foreach($condition as $k=>$v){
$where.=$k."='".$v."' and ";
}
$where='where '.$where .'1=1';
}
$updatastr = '';
if(!empty($data)){
foreach($data as $k=>$v){
$updatastr.= $k."='".$v."',";
}
$updatastr = 'set '.rtrim($updatastr,',');
}
self::$sql = "update {$table} {$updatastr} {$where}";
return mysql_query(self::$sql);
}
/**
* 刪除記錄
*/
public function delete($table,$condition){
$where='';
if(!empty($condition)){
foreach($condition as $k=>$v){
$where.=$k."='".$v."' and ";
}
$where='where '.$where .'1=1';
}
self::$sql = "delete from {$table} {$where}";
return mysql_query(self::$sql);
}
public static function getLastSql(){
echo self::$sql;
}
}
$db = db::getInstance();
//$list = $db->select('demo',array('name'=>'tom','password'=>'ds'),array('name','password'));
//echo $db->insert('demo',array('name'=>'最近你啦','password'=>'123'));
//echo $db->update('demo',array("name"=>'xxx',"password"=>'123'),array('id'=>1));
echo $db->delete('demo',array('id'=>'2'));
db::getLastSql();
echo "pre>";
?>
更多關(guān)于PHP相關(guān)內(nèi)容感興趣的讀者可查看本站專題:《php面向?qū)ο蟪绦蛟O(shè)計(jì)入門教程》、《PHP數(shù)組(Array)操作技巧大全》、《PHP基本語法入門教程》、《PHP運(yùn)算與運(yùn)算符用法總結(jié)》、《php字符串(string)用法總結(jié)》、《php+mysql數(shù)據(jù)庫操作入門教程》及《php常見數(shù)據(jù)庫操作技巧匯總》
希望本文所述對大家PHP程序設(shè)計(jì)有所幫助。
您可能感興趣的文章:- PHP單例模式數(shù)據(jù)庫連接類與頁面靜態(tài)化實(shí)現(xiàn)方法
- PHP中數(shù)據(jù)庫單例模式的實(shí)現(xiàn)代碼分享
- PHP基于單例模式實(shí)現(xiàn)的數(shù)據(jù)庫操作基類
- PHP實(shí)現(xiàn)單例模式最安全的做法
- php單例模式的簡單實(shí)現(xiàn)方法
- php利用單例模式實(shí)現(xiàn)日志處理類庫
- PHP基于單例模式編寫PDO類的方法
- PHP最常用的2種設(shè)計(jì)模式工廠模式和單例模式介紹
- PHP設(shè)計(jì)模式之工廠模式與單例模式
- PHP實(shí)現(xiàn)單例模式建立數(shù)據(jù)庫連接的方法分析