在碼PHP程序的時候,為了以後更好地維護代碼和理解代碼,用一些合適的設計模式是必不可少的,下面我和大家首先分享下單例模式,有錯誤或者不恰當的地方,還望PHPer們幫我指出。
PHP中的對象生存期間是從該腳本開始一直到該腳本結束為止,因此PHP的單例模式只是在一個頁面中(這裡可能包含很多其他頁面,不是狹義的單頁面)多次用到該對象時才會起作用,多次用到時不去重復的new對象(多個人做一個項目時,難免會碰到一次請求中多次實例一個對象的情況),將不會耗費不必要的資源(數據控連接操做效果很明顯),還有一點就是可以保證整個腳本中都是同一個對象,這種模式是怎麼實現的呢,他的實現有幾個要注意的點:
1. 首先就是要將__construct()方法定義為私有方法,這樣就不能通過new來得到一個新的實例了,單例模式不能在外部進行實例化,這能字自身內部進行實例化;
2. 同樣要屏蔽__clone()方法,防止從類外部進行克隆
2. 然後就是定義一個用來保存實例的私有變量和獲取私有變量的公有函數getInstance()。
<?php /** * 設計模式——單例模式 * @author 燕睿濤([email protected]) */ 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 燕睿濤([email protected]) */ 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級的差距,在高並發系統中也是很有用的。我們用它好處多多。
單例模式就這麼多了,下次再講其他設計模式,有什麼不對的地方還望留言或者郵件指出,感激不盡!
send Me~