在碼PHP程序的時候,爲了之後更好地維護代碼和理解代碼,用一些合適的設計模式是必不可少的,下面我和你們首先分享下單例模式,有錯誤或者不恰當的地方,還望PHPer們幫我指出。php
PHP中的對象生存期間是從該腳本開始一直到該腳本結束爲止,所以PHP的單例模式只是在一個頁面中(這裏可能包含不少其餘頁面,不是狹義的單頁面)屢次用到該對象時纔會起做用,屢次用到時不去重複的new對象(多我的作一個項目時,不免會碰到一次請求中屢次實例一個對象的狀況),將不會耗費沒必要要的資源(數據控鏈接操作效果很明顯),還有一點就是能夠保證整個腳本中都是同一個對象,這種模式是怎麼實現的呢,他的實現有幾個要注意的點:mysql
1. 首先就是要將__construct()方法定義爲私有方法,這樣就不能經過new來獲得一個新的實例了,單例模式不能在外部進行實例化,這能字自身內部進行實例化;sql
2. 一樣要屏蔽__clone()方法,防止從類外部進行克隆數據庫
2. 而後就是定義一個用來保存實例的私有變量和獲取私有變量的公有函數getInstance()。設計模式
<?php /** * 設計模式——單例模式 * @author 燕睿濤(luluyrt@163.com) */ class Singlemodel{ /** * 保存Singlemodel實例的變量 * @var Singlemodel $_instance */ private static $_instance = null; /** * 屏蔽掉經過new來實例化該對象 */ private function __construct(){ //空函數就行 } /**
* 屏蔽掉經過clone來克隆該對象
*/
private function __clone(){
//空函數就行
} /** * 經過該方法獲取實例,防止屢次實例化 */ public static function getInstance(){ if(!(self::$_instance instanceof self)){ self::$_instance = new self(); } return self::$_instance; } }
空口無憑,光說這些理論的沒有說服力,下面經過例子來看下具體的效果差別併發
<?php /** * 設計模式——單例模式——測試 * @author 燕睿濤(luluyrt@163.com) */ class Singlemodel{ /** * 保存Singlemodel實例的變量 * @var Singlemodel $_instance */ private static $_instance = null; private $_link = null; /** * 屏蔽掉經過new來實例化該對象(也能夠去掉) * 這裏來測試數據庫鏈接 */ private function __construct(){ $this->_link = mysqli_connect("localhost","root","","mysql"); } /** * 經過該方法獲取實例,防止屢次實例化 */ public static function getInstance(){ if(!(self::$_instance instanceof self)){ self::$_instance = new self(); } return self::$_instance; } /** * 測試1,經過使用單例模式 */ public static function testOne(){ return self::getInstance(); } /** * 測試1,經過使用單例模式 */ public static function testTwo(){ return new self(); } } $obj = array(); $begin = microtime(true); for($i=0;$i<100;$i++){ /* * 這裏進行兩次測試,testOne應用了單例模式,testTwo沒有應用單例模式, * 咱們分別看看他們佔用的資源和耗費的時間 */ //$obj[$i] = Singlemodel::testOne(); $obj[$i] = Singlemodel::testTwo(); } echo "程序運行期間最大內存佔用:".memory_get_peak_usage()."bytes\r"; echo "程序運行耗時:".floatval(microtime(true) - $begin)."s\r";
先註釋$obj[$i] = Singlemodel::testTwo();這一行,使用單例模式,咱們能夠獲得下面的結果函數
而後註釋掉$obj[$i] = Singlemodel::testOne();,使用非單例模式,咱們獲得下面結果高併發
能夠看到性能
100次測試 | 單例模式 | 普通模式 | 普通/單例(倍) |
內存(bytes) | 143816 | 847376 | 5.89 |
時間(s) | 0.0112519 | 0.2541389 | 22.59 |
5次測試 | |||
bytes | 140432 | 168984 | 1.20 |
s | 0.0112612 | 0.0173110 | 1.54 |
能夠看到當一次腳本執行的連接數爲100時單例模式的性能比普通模式在內存佔用方面好了將近6倍,時間上快了將近23倍,當鏈接數繼續增長的時候倍數會更大,由於單例模式耗費的內存和時間基本沒有變化,非單例模式會不停地增大,這裏要注意一點就是非單例模式狀況下連接數增大到必定程度時會報錯"mysqli_connect(): (08004/1040): Trop de connexions in",意思是說併發鏈接太多了,測試咱們能夠經過下面的命令查看mysql最大鏈接數設置,這點須要注意下,省得不知道爲何報錯。測試
show variables like 'max_connections';
到這裏,你要是本身測試過就會發現,當連接次數比較少時,差別是比較小的(就像上面的一次請求有5次鏈接時),其實在一次請求中達到不少次實例化也是比較少的,那麼是否是說這個就沒做用了呢,固然不是,你想一想看,首先,這樣能夠儘可能避免屢次實例化,減少資源消耗;其次,就算是這10ms級的差距,在高併發系統中也是頗有用的。咱們用它好處多多。
單例模式就這麼多了,下次再講其餘設計模式,有什麼不對的地方還望留言或者郵件指出,感激涕零!