在碼PHP程式的時候,為了以後更好地維護程式碼和理解程式碼,用一些合適的設計模式是必不可少的,下面我和大家首先分享下單例模式,有錯誤或者不恰當的地方,還望PHPer們幫我指出。
PHP中的物件生存期間是從該腳本開始一直到該腳本結束為止,因此PHP的單例模式只是在一個頁面中(這裡可能包含很多其他頁面,不是狹義的單頁)多次用到該對象時才會起作用,多次用到時不去重複的new物件(多個人做一個專案時,難免會碰到一次請求中多次實例一個物件的情況),將不會耗費不必要的資源(資料控連接操做效果很明顯),還有一點就是可以保證整個腳本中都是同一個對象,這種模式是怎麼實現的呢,他的實現有幾個要注意的點:
1. 首先就是要將__construct()方法定義為私有方法,這樣就不能透過new來得到一個新的實例了,單例模式不能在外部進行實例化,這能字自身內部進行實例化;
2. 同樣要屏蔽__clone()方法,防止從類別外部進行克隆
2. 然後就是定義一個用來保存實例的私有變數和取得私有變數的公有函數getInstance()。
<?<span>php </span><span>/*</span><span>* * 设计模式——单例模式 * @author 燕睿涛(luluyrt@163.com) </span><span>*/</span> <span>class</span><span> Singlemodel{ </span><span>/*</span><span>* * 保存Singlemodel实例的变量 * @var Singlemodel $_instance </span><span>*/</span> <span>private</span> <span>static</span> <span>$_instance</span> = <span>null</span><span>; </span><span>/*</span><span>* * 屏蔽掉通过new来实例化该对象 </span><span>*/</span> <span>private</span> <span>function</span><span> __construct(){ </span><span>//</span><span>空函数就行</span> <span> } <span> /*</span><span>*</span></span>
<span><span> * 屏蔽掉通过clone来克隆该对象</span></span>
<span><span>*/</span> </span>
<span> <span>private</span> <span>function</span><span> __clone(){ </span></span>
<span><span>//</span><span>空函数就行</span> </span>
<span> <span>}</span> </span><span>/*</span><span>* * 通过该方法获取实例,防止多次实例化 </span><span>*/</span> <span>public</span> <span>static</span> <span>function</span><span> getInstance(){ </span><span>if</span>(!(self::<span>$_instance</span><span> instanceof self)){ self</span>::<span>$_instance</span> = <span>new</span><span> self(); } </span><span>return</span> self::<span>$_instance</span><span>; } }</span>
空口無憑,光說這些理論的沒有說服力,下面透過例子來看下具體的效果差異
<?<span>php </span><span>/*</span><span>* * 设计模式——单例模式——测试 * @author 燕睿涛(luluyrt@163.com) </span><span>*/</span> <span>class</span><span> Singlemodel{ </span><span>/*</span><span>* * 保存Singlemodel实例的变量 * @var Singlemodel $_instance </span><span>*/</span> <span>private</span> <span>static</span> <span>$_instance</span> = <span>null</span><span>; </span><span>private</span> <span>$_link</span> = <span>null</span><span>; </span><span>/*</span><span>* * 屏蔽掉通过new来实例化该对象(也可以去掉) * 这里来测试数据库连接 </span><span>*/</span> <span>private</span> <span>function</span><span> __construct(){ </span><span>$this</span>->_link = <span>mysqli_connect</span>("localhost","root","","mysql"<span>); } </span><span>/*</span><span>* * 通过该方法获取实例,防止多次实例化 </span><span>*/</span> <span>public</span> <span>static</span> <span>function</span><span> getInstance(){ </span><span>if</span>(!(self::<span>$_instance</span><span> instanceof self)){ self</span>::<span>$_instance</span> = <span>new</span><span> self(); } </span><span>return</span> self::<span>$_instance</span><span>; } </span><span>/*</span><span>* * 测试1,通过使用单例模式 </span><span>*/</span> <span>public</span> <span>static</span> <span>function</span><span> testOne(){ </span><span>return</span> self::<span>getInstance(); } </span><span>/*</span><span>* * 测试1,通过使用单例模式 </span><span>*/</span> <span>public</span> <span>static</span> <span>function</span><span> testTwo(){ </span><span>return</span> <span>new</span><span> self(); } } </span><span>$obj</span> = <span>array</span><span>(); </span><span>$begin</span> = <span>microtime</span>(<span>true</span><span>); </span><span>for</span>(<span>$i</span>=0;<span>$i</span><100;<span>$i</span>++<span>){ </span><span>/*</span><span> * 这里进行两次测试,testOne应用了单例模式,testTwo没有应用单例模式, * 我们分别看看他们占用的资源和耗费的时间 </span><span>*/</span> <span>//</span><span>$obj[$i] = Singlemodel::testOne();</span> <span>$obj</span>[<span>$i</span>] = Singlemodel::<span>testTwo(); } </span><span>echo</span> "程序运行期间最大内存占用:".memory_get_peak_usage()."bytes\r"<span>; </span><span>echo</span> "程序运行耗时:".<span>floatval</span>(<span>microtime</span>(<span>true</span>) - <span>$begin</span>)."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 <span>like</span> <span>'</span><span>max_connections</span><span>'</span>;
到這裡,你要是自己測試過就會發現,當鏈結次數比較少時,差異是比較小的(就像上面的一次請求有5次連接時),其實在一次請求中達到很多次實例化也是比較少的,那麼是不是說這個就沒作用了呢,當然不是,你想想看,首先,這樣可以盡量避免多次實例化,減小資源消耗;其次,就算是這10ms級的差距,在高並發系統中也是很有用的。我們用它好處多多。
單例模式就這麼多了,下次再講其他設計模式,有什麼不對的地方還望留言或者郵件指出,感激不盡!
send Me~
以上就介紹了PHP設計模式(一),包含了方面的內容,希望對PHP教程有興趣的朋友有幫助。