一直以來都是在寫項目卻從來沒有仔細分析過什麼是單例模式,單例模式分為幾種,單例模式有什麼特點。今天隨便記錄一個隨筆,全當是複習複習做個筆記。 單例模式要確保某個類只有一個實例,而且自動實例化並向整個系統提供實例。單例模式分為3種:餓漢單例模式、懶漢單例模式、登記式單例模式。 單例模式有3個特點: 單 ...
一直以來都是在寫項目卻從來沒有仔細分析過什麼是單例模式,單例模式分為幾種,單例模式有什麼特點。今天隨便記錄一個隨筆,全當是複習複習做個筆記。
單例模式要確保某個類只有一個實例,而且自動實例化並向整個系統提供實例。單例模式分為3種:餓漢單例模式、懶漢單例模式、登記式單例模式。
單例模式有3個特點:
- 只有一個實例
- 必須自行創建這個實例
- 必須給其他對象提供這個實例
單例模式常被應用到資料庫連接,這種耗費資源的操作。類的結構分為3私1公/4私1公。下麵就編寫一個簡單的單例模式:
1 <?php 2 3 class db { 4 5 private $config = 1; 6 7 //私有的靜態變數,預設值為null 8 private static $instance = null; 9 10 /** 11 * 私有構造方法 12 * 防止多個實例 13 */ 14 private function __construct($config) { 15 echo '我是私有構造方法<br>'; 16 } 17 18 /** 19 * 私有克隆方法 20 * 防止多個實例 21 */ 22 private function __clone() { 23 24 } 25 26 /** 27 * 防止反序列化 28 */ 29 private function __wakeup() { 30 31 } 32 33 /** 34 * 公有靜態方法 35 * 判斷$instance是否實例化,存在實例化對象就直接返回,不存在實例化對象就new實例化 36 */ 37 public static function getInstance() { 38 if(is_null(self::$instance)) { 39 self::$instance = new self(); 40 } 41 return self::$instance; 42 } 43 } 44 45 $db = db::getInstance(); 46 var_dump($db); 47 $db = db::getInstance(); 48 var_dump($db);
執行結果:
可以看到兩次執行的句柄都一樣是同一個實例。接下來把這個單例完善一下變成一個資料庫連接的單例模式:
1 <?php 2 3 class db { 4 5 //私有link變數 6 private $link; 7 8 private $config = [ 9 'host' => 'localhost', 10 'username' => 'root', 11 'password' => 'root', 12 'databases' => '', 13 'port' => 3306, 14 'conding' => 'utf8' 15 ]; 16 17 18 //私有的靜態變數,預設值為null 19 private static $instance = null; 20 21 /** 22 * 私有構造方法 23 * 防止多個實例 24 * array $config 資料庫配置 25 */ 26 private function __construct($config) { 27 //判斷$config配置是否設置,並且是數組 28 if(isset($config) && is_array($config)) { 29 //存在配置,和預設配置合併,用新的配置替換預設配置 30 $this->config = array_merge($this->config, $config); 31 } 32 //創建資料庫連接 33 $this->link = mysqli_connect($this->config['host'], $this->config['username'], $this->config['password'], $this->config['databases'], $this->config['port']); 34 35 //輸出連接錯誤 36 $this->connect_errno(); 37 38 if($this->config['databases']) { 39 $conding = $this->config['conding']; 40 $this->query("SET NAMES '{$condig}'"); 41 } 42 43 return $this->link; 44 } 45 46 /** 47 * 私有克隆方法 48 * 防止多個實例 49 */ 50 private function __clone() { 51 52 } 53 54 /** 55 * 防止反序列化 56 */ 57 private function __wakeup() { 58 59 } 60 61 /** 62 * 公有靜態方法 63 * 判斷$instance是否實例化,存在實例化對象就直接返回,不存在實例化對象就new實例化 64 * array $config 資料庫配置 65 */ 66 public static function getInstance($config) { 67 //判斷變數$instance是否存在實例化對象,不存在 68 if(is_null(self::$instance)) { 69 //自動實例化,給構建方法傳$config配置 70 self::$instance = new self($config); 71 } 72 //返回$instance實例化對象 73 return self::$instance; 74 } 75 76 /** 77 * 執行sql 78 * $query sql語句 79 */ 80 public function query($query) { 81 $this->result = mysqli_query($this->link, $query); 82 return $this->result; 83 } 84 85 /** 86 * 選擇資料庫 87 * string $dbname 資料庫名稱 88 */ 89 public function select_db($dbname) { 90 $this->result = mysqli_select_db($this->link, $dbname); 91 $conding = $this->config['conding']; 92 $this->query("SET NAMES '{$condig}'"); 93 return $this->result; 94 } 95 96 /** 97 * 查詢一條或多條數據 98 * string $sql sql語句 99 * MYSQLI_NUM、MYSQLI_ASSOC、MYSQLI_BOTH 100 */ 101 public function fetch_array($sql, $type = MYSQLI_BOTH) { 102 $result = $this->query($sql); 103 $rows = mysqli_fetch_array($result, $type); 104 if($this->num_rows($result) > 1) { 105 while($rows) { 106 $this->rows[] = $rows; 107 } 108 } else { 109 $this->rows = $rows; 110 } 111 return $this->rows; 112 } 113 114 public function num_rows($result) { 115 $this->result = mysqli_num_rows($result); 116 return $this->result; 117 } 118 119 /** 120 * 輸出連接錯誤 121 */ 122 private function connect_errno() { 123 if(mysqli_connect_errno($this->link)) { 124 echo 'MySQL資料庫連接失敗,錯誤代碼ERROR:' . mysqli_connect_errno() . '<br>'; 125 } 126 } 127 128 /** 129 * 關閉資料庫連接 130 */ 131 public function close() { 132 $this->result = mysqli_close($this->link); 133 return $this->result; 134 } 135 136 137 } 138 139 $config = [ 140 'host' => '172.17.0.2', 141 'username' => 'root', 142 'password' => 'cuiyuanxin66666', 143 // 'databases' => 'nndb' 144 ]; 145 $db = db::getInstance($config); 146 $db1 = db::getInstance($config); 147 //判斷兩個實例對象是否一致 148 if($db === $db1) { 149 echo '一致'; 150 echo '<br>'; 151 } else { 152 echo '不一致'; 153 echo '<br>'; 154 } 155 //切換資料庫hkxy 156 $db->select_db('hkxy'); 157 $sql = 'select * from qii_admin_menu limit 1'; 158 $rows = $db->fetch_array($sql, MYSQLI_ASSOC); 159 var_dump($db); 160 echo '<br>-----------------------------------------<br>'; 161 var_dump($rows); 162 echo '<br>-----------------------------------------<br>'; 163 $db->select_db('nndb'); 164 $sql = 'select * from niuniu_user limit 1'; 165 $rows = $db->fetch_array($sql, MYSQLI_ASSOC); 166 var_dump($rows);
經過改造一個連接資料庫的單例模式就寫完了,看一下執行結果:
通過代碼來看兩個實例對象完全一樣。
源代碼已上傳GitHub:https://github.com/cuiyuanxin/php-demo/blob/master/db.php
純手打筆記,如有錯誤請評論提出,謝謝。