PHP中”單例模式“執行個體講解

來源:互聯網
上載者:User

假設我們需要寫一個類用來操作資料庫,並同時滿足以下要求:

①SqlHelper類只能有一個執行個體(不能多)
②SqlHelper類必須能夠自行建立這個執行個體
③必須自行向整個系統提供這個執行個體,換句話說:多個對象共用一塊記憶體地區,比如,對象A設定了某些屬性值,則對象B,C也可以訪問這些屬性值(結尾的例子很好的說明了這個問題)

 1 <?php 2     class SqlHelper{ 3         private static $_instance; 4         public $_dbname; 5         private function __construct(){ 6              7         } 8         public function getDbName(){ 9             echo $this->_dbname;10         }11         public function setDbName($dbname){12             $this->_dbname=$dbname;13         }14         public function clear(){15             unset($this->_dbname);16         }17         18     }19     $sqlHelper=new SqlHelper();//列印:Fatal error: Call to private SqlHelper::__construct() from invalid context 20 ?>

以上的SqlHelper類是無法從自身的類外部建立執行個體的,因為我們將建構函式設為了private,所以通過new SqlHelper()是無法從類外部使用私人的建構函式的,如果強制使用,將會報如下錯誤:
Fatal error: Call to private SqlHelper::__construct() from invalid context
嚴重錯誤:從上下文中調用了一個私人的建構函式SqlHelper::__construct()

按照已往的思維邏輯,執行個體化一個類都是直接在類外部使用new操作符的,但是既然這裡講建構函式設為private了,我們知道,私人的成員屬性或函數只能在類的內部被訪問,所以我們可以通過在類SqlHelper內部再建立一個函數(比如:getInstance()),而且必須是public的,getInstance()函數中主要進行的是執行個體化SqlHelper類
比如:

 1 <?php 2     class SqlHelper{ 3         private $_instance; 4         //......省略 5         public function getInstance(){ 6             $this->_instance=new SqlHelper(); 7         } 8         //......省略 9     }10 ?>

但是問題出現了,
①我們在調用getInstance()之前沒有執行個體化SqlHelper對象,所以也就無法通過對象的方式來調用getInstance()函數了,
②既然在調用getInstance的時候還未執行個體化出對象,所以在getInstance函數中使用$this肯定也會報錯(Fatal error: Using $this when not in object context)
那如何解決呢?

解決途徑:我們可以講getInstance()方法設為靜態,根據靜態定義,她只能被類而不是對象調用,將$_instance也設為靜態即可。所以這個方法正好符合我們的口味。
所以我們進一步將代碼修改如下:

 1 <?php 2     class SqlHelper{ 3         private static $_instance; 4         private function __construct(){ 5             echo "建構函式被調用"; 6         }         7         //......省略 8         public static function getInstance(){ 9             if (self::$_instance===null) {10 //                self::$_instance=new SqlHelper();//方式一11                 self::$_instance=new self();//方式二                12             }13             return self::$_instance;14         }15         //......省略16     }17     $sqlHelper=SqlHelper::getInstance();//列印:建構函式被調用18 ?>

通過在getInstance函數中對當前記憶體中有誤存在當類類的一個執行個體進行判斷,如果沒有則執行個體化,並返回物件控點,如果有則直接返回該物件控點
至此,完整代碼如下所示:

 1 <?php 2     class SqlHelper{ 3         private static $_instance; 4         public $_dbname; 5         private function __construct(){ 6              7         } 8         //getInstance()方法必須設定為公有的,必須調用此方法 9         public static function getInstance(){10             //對象方法不能訪問普通的對象屬性,所以$_instance需要設為靜態11             if (self::$_instance===null) {12 //                self::$_instance=new SqlHelper();//方式一    13                 self::$_instance=new self();//方式二        14             }15             return self::$_instance;16         }17         public function getDbName(){18             echo $this->_dbname;19         }20         public function setDbName($dbname){21             $this->_dbname=$dbname;22         }23     }24 //    $sqlHelper=new SqlHelper();//列印:Fatal error: Call to private SqlHelper::__construct() from invalid context 25     $A=SqlHelper::getInstance();26     $A->setDbName('資料庫名');27     $A->getDbName();28 //    unset($A);//移除引用29     $B=SqlHelper::getInstance();30     $B->getDbName();31     $C=SqlHelper::getInstance();32     $C->getDbName();33     34 ?>

以上代碼的執行結果:
資料庫名//$A->getDbName();

資料庫名//$B->getDbName();
資料庫名//$C->getDbName();
也就是說,對象A,B,C實際上都是使用同一個對象執行個體,訪問的都是同一塊記憶體地區
所以,即使unset($A),對象B和C還是照樣能夠通過getDbName()方法輸出“資料庫名”的
unset($A)實際上只是將對象A與某塊記憶體位址(該對象的執行個體所在的地址)之間的連絡方式斷開而已,跟對象B和對象C無關,可以用用一張圖表示如下

 

原創文章:MarcoFly

轉載請註明出處:http://www.cnblogs.com/hongfei/archive/2012/07/07/2580994.html

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.