以前剛開始工作的時候經常連接數據庫,每次用到數據庫的時候就要用new進行實例並連接一次,當時因為連接數據庫的次數不是很頻繁,所以也沒什么。后來主管對我說我現在這樣每次都連接數據庫的如果數據讀取頻繁的話對數據庫和系統造成的壓力會很大,讓我想想辦法能不能就連接一次數據庫然后再次用到的時候就不用new一個新的連接了,當時怎么也沒想到好的辦法,知道最近學到了單例模式才恍然大悟,當時主管是引導我用單例模式的,只怪我以前對開發模式不懂。好了廢話少說,下面來看單例模式:
單例模式(職責模式):
簡單的說,一個對象(在學習設計模式之前,需要比較了解面向對象思想)只負責一個特定的任務;
單例類:
1、構造函數需要標記為private(訪問控制:防止外部代碼使用new操作符創建對象),單例類不能在其他類中實例化,只能被其自身實例化;
2、擁有一個保存類的實例的靜態成員變量
3、擁有一個訪問這個實例的公共的靜態方法(常用getInstance()方法進行實例化單例類,通過instanceof操作符可以檢測到類是否已經被實例化)
另外,需要創建__clone()方法防止對象被復制(克隆)
為什么要使用PHP單例模式?
1、php的應用主要在於數據庫應用, 所以一個應用中會存在大量的數據庫操作, 使用單例模式, 則可以避免大量的new 操作消耗的資源。
2、如果系統中需要有一個類來全局控制某些配置信息, 那么使用單例模式可以很方便的實現. 這個可以參看ZF的FrontController部分。
3、在一次頁面請求中, 便於進行調試, 因為所有的代碼(例如數據庫操作類db)都集中在一個類中, 我們可以在類中設置鈎子, 輸出日志,從而避免到處var_dump, echo。
代碼(官方文檔中的):
<?php
class Singletons{
// 保存類實例在此屬性中
private static $instance;
// 構造方法聲明為private,防止直接創建對象
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!';
}
// 阻止用戶復制對象實例
public function __clone()
{
trigger_error('Clone is not allowed.',E_USER_ERROR);
}
}//endclass singletons
//這個寫法會出錯,因為構造方法被聲明為private
//$test= new Singletons();
// 下面將得到Example類的單例對象
$test= Singletons::singleton();
$test->bark();
// 復制對象將導致一個E_USER_ERROR.
$test_clone= clone $test;
?>
結果:
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
以下內容源自網絡(可以參考學習一下):
單例模式的三個要點:
(1). 需要一個保存類的唯一實例的靜態成員變量:
[php] view plaincopyprint?
1. private static $_instance;
(2). 構造函數和克隆函數必須聲明為私有的,防止外部程序new類從而失去單例模式的意義:
[php] view plaincopyprint?
1. private function __construct()
2. {
3. $this->_db = pg_connect('xxxx');
4. }
5. private function __clone()
6. {
7. }//覆蓋__clone()方法,禁止克隆
8.
(3). 必須提供一個訪問這個實例的公共的靜態方法(通常為getInstance方法),從而返回唯一實例的一個引用
[php] view plaincopyprint?
1. public static function getInstance()
2. {
3. if(! (self::$_instance instanceof self) )
4. {
5. self::$_instance = new self();
6. }
7. return self::$_instance;
8.
9. }
二、為什么要使用單例模式?
1、PHP缺點:
PHP語言是一種解釋型的腳本語言,這種運行機制使得每個PHP頁面被解釋執行后,所有的相關資源都會被回收。也就是說,PHP在語言級別上沒有辦法讓某個對象常駐內存,這和asp.NET、Java等編譯型是不同的,比如在Java中單例會一直存在於整個應用程序的生命周期里,變量是跨頁面級的,真正可以做到這個實例在應用程序生命周期中的唯一性。然而在PHP中,所有的變量無論是全局變量還是類的靜態成員,都是頁面級的,每次頁面被執行時,都會重新建立新的對象,都會在頁面執行完畢后被清空,這樣似乎PHP單例模式就沒有什么意義了,所以PHP單例模式我覺得只是針對單次頁面級請求時出現多個應用場景並需要共享同一對象資源時是非常有意義的。
2、單例模式在PHP中的應用場合:
(1)、應用程序與數據庫交互
一個應用中會存在大量的數據庫操作,比如過數據庫句柄來連接數據庫這一行為,使用單例模式可以避免大量的new操作,因為每一次new操作都會消耗內存資源和系統資源。
(2)、控制配置信息
如果系統中需要有一個類來全局控制某些配置信息,那么使用單例模式可以很方便的實現.
三、如何實現單例模式?
1、普通的數據庫訪問例子:
[php] view plaincopyprint?
1. <?php
2. ......
3. //初始化一個數據庫句柄
4. $db = new DB(...);
5.
6. //添加用戶信息
7. $db->addUserInfo(...);
8.
9. ......
10.
11.//在函數中訪問數據庫,查找用戶信息
12.function getUserInfo()
13.{
14. $db = new DB(...);//再次new 數據庫類,和數據庫建立連接
15. $db = query(....);//根據查詢語句訪問數據庫
16.}
17.
18.?>
2、應用單例模式對數據庫進行操作:
[php] view plaincopyprint?
1. <?php
2.
3. class DB
4. {
5. private $_db;
6. private static $_instance;
7.
8. private function __construct(...)
9. {
10. $this->_db = pg_connect(...);//postgrsql
11. }
12.
13. private function __clone() {}; //覆蓋__clone()方法,禁止克隆
14.
15. public static function getInstance()
16. {
17. if(! (self::$_instance instanceof self) ) {
18. self::$_instance = new self();
19. }
20. return self::$_instance;
21. }
22.
23.
24.
25. public function addUserInfo(...)
26. {
27.
28.
29.
30. }
31.
32. public function getUserInfo(...)
33. {
34.
35. }
36.
37.}
38.
39.//test
40.
41.$db = DB::getInstance();
42.
43.$db->addUserInfo(...);
44.
45.$db->getUserInfo(...);
46.
47.
48.?>
3、深入理解
[php] view plaincopyprint?
1. <?php
2. class db {
3. public $conn;
4. public static $sql;
5. public static $instance=null;
6. private function __construct(){
7. require_once('db.config.php');
8. $this->conn = mysql_connect($db['host'],$db['user'],$db['password']);
9. if(!mysql_select_db($db['database'],$this->conn)){
10. echo "失敗";
11. };
12. mysql_query('set names utf8',$this->conn);
13. }
14. public static function getInstance(){
15. if(is_null(self::$instance)){
16. self::$instance = new db;
17. }
18. return self::$instance;
19. }
20. /**
21. * 查詢數據庫
22. */
23. public function select($table,$condition=array(),$field = array()){
24. $where='';
25. if(!empty($condition)){
26.
27. foreach($condition as $k=>$v){
28. $where.=$k."='".$v."' and ";
29. }
30. $where='where '.$where .'1=1';
31. }
32. $fieldstr = '';
33. if(!empty($field)){
34.
35. foreach($field as $k=>$v){
36. $fieldstr.= $v.',';
37. }
38. $fieldstr = rtrim($fieldstr,',');
39. }else{
40. $fieldstr = '*';
41. }
42. self::$sql = "select {$fieldstr} from {$table} {$where}";
43. $result=mysql_query(self::$sql,$this->conn);
44. $resuleRow = array();
45. $i = 0;
46. while($row=mysql_fetch_assoc($result)){
47. foreach($row as $k=>$v){
48. $resuleRow[$i][$k] = $v;
49. }
50. $i++;
51. }
52. return $resuleRow;
53. }
54. /**
55. * 添加一條記錄
56. */
57. public function insert($table,$data){
58. $values = '';
59. $datas = '';
60. foreach($data as $k=>$v){
61. $values.=$k.',';
62. $datas.="'$v'".',';
63. }
64. $values = rtrim($values,',');
65. $datas = rtrim($datas,',');
66. self::$sql = "INSERT INTO {$table} ({$values}) VALUES ({$datas})";
67. if(mysql_query(self::$sql)){
68. return mysql_insert_id();
69. }else{
70. return false;
71. };
72. }
73. /**
74. * 修改一條記錄
75. */
76. public function update($table,$data,$condition=array()){
77. $where='';
78. if(!empty($condition)){
79.
80. foreach($condition as $k=>$v){
81. $where.=$k."='".$v."' and ";
82. }
83. $where='where '.$where .'1=1';
84. }
85. $updatastr = '';
86. if(!empty($data)){
87. foreach($data as $k=>$v){
88. $updatastr.= $k."='".$v."',";
89. }
90. $updatastr = 'set '.rtrim($updatastr,',');
91. }
92. self::$sql = "update {$table} {$updatastr} {$where}";
93. return mysql_query(self::$sql);
94. }
95. /**
96. * 刪除記錄
97. */
98. public function delete($table,$condition){
99. $where='';
100. if(!empty($condition)){
101.
102. foreach($condition as $k=>$v){
103. $where.=$k."='".$v."' and ";
104. }
105. $where='where '.$where .'1=1';
106. }
107. self::$sql = "delete from {$table} {$where}";
108. return mysql_query(self::$sql);
109.
110. }
111.
112. public static function getLastSql(){
113. echo self::$sql;
114. }
115.
116.
117.
118.}
119.
120.$db = db::getInstance();
121.//$list = $db->select('demo',array('name'=>'tom','password'=>'ds'),array('name','password'));
122.//echo $db->insert('demo',array('name'=>'最近你啦','password'=>'123'));
123.//echo $db->update('demo',array("name"=>'xxx',"password"=>'123'),array('id'=>1));
124.echo $db->delete('demo',array('id'=>'2'));
125.db::getLastSql();
126.echo "<pre>";
127.?>