PHP单例模式(精讲)
2019獨角獸企業重金招聘Python工程師標準>>>
首先我們要明確單例模式這個概念,那么什么是單例模式呢?
單例模式顧名思義,就是只有一個實例。作為對象的創建模式,單例模式確保某一個類只有一個實例,而且自行實例化并向整個系統提供這個實例,這個類我們稱之為單例類。
單例模式的要點有三個:
一是某個類只能有一個實例;
二是它必須自行創建這個實例;
三是它必須自行向整個系統提供這個實例。
<?php /* 單例模式舉例,其要點如下:** 1. $_instance 必須聲明為靜態的私有變量* 2. 構造函數和克隆函數必須聲明為私有的,這是為了防止外部程序 new 類從而失去單例模式的意義* 3. getInstance()方法必須聲明為公有的,必須調用此方法以返回唯一實例的一個引用* 4. ::操作符只能訪問靜態變量或靜態函數* 5. PHP的單例模式是相對而言的,因為PHP的解釋運行機制使得每個PHP頁面被解釋執行后,所有的相關資源都會被回收。* 也就是說,PHP在語言級別上沒有辦法讓某個對象常駐內存。在PHP中,所有的變量都是頁面級的,無論是全局變量,* 還是類的靜態成員,都會在頁面執行完畢后被清空,結果會重新建立新的對象,這樣也就完全失去了Singleton的意義。* 不過,在實際應用中同一個頁面中可能會存在多個業務邏輯,這時單例模式就起到了很重要的作用,有效的避免了重復* new 對象(注: new 對象會消耗內存資源)這么一個行為,所以我們說PHP的單例模式是相對而言的* */ class People {static private $_instance = NULL;public $height = '';public $age = '';private function __construct() {$this->height = '185';$this->age = 25;}private function __clone() {//do something}static public function getInstance() {if (!self::$_instance instanceof self) {//echo 'lgh-big';self::$_instance = new self;} else {//for testing only//echo 'gdc-xiaoairener';}return self::$_instance;}public function getHeight() {echo $this->height;}public function getAge() {echo $this->age;} } function testInstance() {People::getInstance()->getAge(); } //begin to use the class $lgh = People::getInstance(); $lgh->getHeight(); echo '<br />'; testInstance(); ?>下面我們討論下為什么要使用PHP單例模式?
多數人都是從單例模式的字面上的意思來理解它的用途, 認為這是對系統資源的節省, 可以避免重復實例化, 是一種"計劃生育"。而PHP每次執行完頁面都是會從內存中清理掉所有的資源。因而PHP中的單例實際每次運行都是需要重新實例化的,這樣就失去了單例重復實例化的意義了。單單從這個方面來說,PHP的單例的確有點讓各位失望。但是單例僅僅只有這個功能和應用嗎?答案是否定的,我們一起來看看。
1. php的應用主要在于數據庫應用, 所以一個應用中會存在大量的數據庫操作,在使用面向對象的方式開發時,如果使用單例模式,則可以避免大量的new 操作消耗的資源。
2. 如果系統中需要有一個類來全局控制某些配置信息,那么使用單例模式可以很方便的實現。這個可以參看zend Framework的FrontController部分。
3. 在一次頁面請求中,便于進行調試,因為所有的代碼(例如數據庫操作類db)都集中在一個類中,我們可以在類中設置鉤子,輸出日志,從而避免到處var_dump, echo。
使用傳統方式編碼
<?php //初始化一個數據庫句柄 $db = new DB(); //比如有個應用場景是添加一條用戶信息: $db->addUserInfo(); //然而我們在另外一個地方可能要查找用戶的信息,這個情景出現在一個函數中,這時要用到數據庫句柄資源,我們可能需要這么去做 function test() {//這時我們不得不重新初始化一個數據庫句柄,試想多個應用場景下,這樣的代碼是多么可怕啊?!$db = new DB();$db->getUserInfo();//有些朋友或許會說,我也可以不這樣做啊,我直接利用global關鍵字不就可以了嗎?的確,global可以解決問題,也起到了單例模式的作用,但是OOP中,我們拒絕這樣來編寫代碼,因為global存在安全隱患,請參考相關書籍,同時單例模式恰恰是對全局變量的一種改進,避免了那些存儲唯一實例的全局變量污染命名空間global $db; //OOP中,我們不提倡這樣編寫代碼 }使用單例模式編碼
<?php //所有的應用情景只有一個數據庫句柄資源,嘿嘿,效率老高了, //資源也大大的得到節省,代碼簡潔明了:) DB::getInstance()->addUserInfo(); DB::getInstance()->getUserInfo();PHP單例模式實現的核心要點有如下三條:
1.需要一個保存類的唯一實例的靜態成員變量(通常為$_instance私有變量)
2.構造函數和克隆函數必須聲明為私有的,這是為了防止外部程序new類從而失去單例模式的意義
3.必須提供一個訪問這個實例的公共的靜態方法(通常為getInstance方法),從而返回唯一實例的一個引用
在了解了單例模式的應用場景之后,下面我們通過編寫單例模式的具體實現代碼來掌握PHP單例模式的核心要點,代碼如下:
<?php /*** PHP單例模式演示舉例* @author guohua.li* @modify 2010-07-11* @website http://blog.163.com/lgh_2002/*/ class User {/*** 靜態成品變量 保存全局實例* @access private*/static private $_instance = NULL;/*** 私有化構造函數,防止外界實例化對象*/private function __construct() {}/*** 私有化克隆函數,防止外界克隆對象*/private function __clone() {}/*** 靜態方法, 單例統一訪問入口* @return object 返回對象的唯一實例*/static public function getInstance() {if (is_null(self::$_instance) || !isset(self::$_instance)) {self::$_instance = new self();}return self::$_instance;}/*** 測試方法: 獲取用戶名字*/public function getName() {echo 'hello liguohua!';} }PHP單例模式的缺點
眾所周知,PHP語言是一種解釋型的腳本語言,這種運行機制使得每個PHP頁面被解釋執行后,所有的相關資源都會被回收。也就是說,PHP在語言級別上沒有辦法讓某個對象常駐內存,這和asp.net、Java等編譯型是不同的,比如在Java中單例會一直存在于整個應用程序的生命周期里,變量是跨頁面級的,真正可以做到這個實例在應用程序生命周期中的唯一性。然而在PHP中,所有的變量無論是全局變量還是類的靜態成員,都是頁面級的,每次頁面被執行時,都會重新建立新的對象,都會在頁面執行完畢后被清空,這樣似乎PHP單例模式就沒有什么意義了,所以PHP單例模式我覺得只是針對單次頁面級請求時出現多個應用場景并需要共享同一對象資源時是非常有意義的。
參考鏈接:
http://www.cnblogs.com/zox2011/archive/2011/09/20/2182119.html
轉載于:https://my.oschina.net/jiangbianwanghai/blog/903676
總結
以上是生活随笔為你收集整理的PHP单例模式(精讲)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 静态属性,函数闭包,call/apply
- 下一篇: oracle dba 手动创建数据实例