PHP 單例模式優點意義及如何實現

来源:https://www.cnblogs.com/lienen/archive/2019/03/05/10474329.html
-Advertisement-
Play Games

一、什麼是單例模式?1、含義 作為對象的創建模式,單例模式確保某一個類只有一個實例,而且自行實例化並向整個系統全局地提供這個實例。它不會創建實例副本,而是會向單例類內部存儲的實例返回一個引用。2、單例模式的三個要點:(1). 需要一個保存類的唯一實例的靜態成員變數:private static $_ ...


一、什麼是單例模式?

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、普通的資料庫訪問例子:

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 <?php   ......   //初始化一個資料庫句柄   $db new DB(...);       //添加用戶信息   $db->addUserInfo(...);       ......       //在函數中訪問資料庫,查找用戶信息   function getUserInfo()   {       $db new DB(...);//再次new 資料庫類,和資料庫建立連接       $db = query(....);//根據查詢語句訪問資料庫   }       ?>




2、應用單例模式對資料庫進行操作:

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 <?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操作資料庫類的一個封裝,採用了單例模式:

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 <?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');         } <a href="\"/tags.php/catch/\"" target="\"_blank\"">catch</a> (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 '';             <a href="\"/tags.php/foreach/\"" target="\"_blank\"">foreach</a> ($arrayDataValue as $key => $value) {                 $strSql .= ", `$key`='$value'";             }             $strSql = <a href="\"/tags.php/substr/\"" target="\"_blank\"">substr</a>($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->d
您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 前端時間,做一個小網站的時候,需要用到很多小圖標,UI設計好之後不知道如何使用,如果使用圖片那會很麻煩,相信一些前端更喜歡iconfont這樣的標簽直接調用,這樣包括顏色和大小以及使用都更方便快捷,於是我們經過交流之後決定使用阿裡巴巴適量圖標庫,這是我們第一次使用,也順便把經驗分享給大家,希望可以對 ...
  • 來自:https://blog.csdn.net/qq_38658877/article/details/78092649 侵刪 Document ...
  • 來自:https://blog.csdn.net/qq_38658877/article/details/78092649 侵刪 Document ...
  • 來自:https://blog.csdn.net/sheng_li/article/details/84347987 侵刪<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" cont ...
  • 註意的是: 加上了冒號是為了動態綁定數據,等號後面可以寫變數。如果不使用冒號,等號後面就可以寫字元串等原始類型數據。這是就無法進行動態綁定數據了 ...
  • 在做js開發的時候用到了startsWith函數時,發現各個瀏覽器不相容問題,因為對開發來說,chrome瀏覽器最好用,就一直在chrome瀏覽器中使用這兩個函數沒有任何問題,但在ie瀏覽器訪問就直接報錯,因為ie沒有這兩個函數,要麼修改方法,換別的方法,但是一兩個還好改,多了就不好改,這個時候就只 ...
  • ""中文編程"知乎專欄原鏈" 在前文 "對在代碼中使用中文命名的質疑與回應" 中闡述了在代碼中使用中文命名的益處. 此文將從軟體使用者的角度闡述對API中文化的意義並探討實現途徑. 當然, 文中面向的用戶是以中文為母語的開發者. 首先請看一個 "實例" , 演示效果在 "此" : 這個庫提供了一系列 ...
  • 一、入門 1、jquery 就是一個js的框架; 2、好處就是能讓我們的js代碼寫的更少; 3、基本使用:引入script,後面使用即可; 4、關於版本選擇:1.* 版本的相容性比較好,大公司用的多; 5、關於壓縮版和為壓縮版:開發用未壓縮的便於看源碼學習,生產環境用壓縮版可以提高速度; 二、jQu ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...