標籤:api 設計模式 php單例模式 單例模式的繼承 php
今天來說一說單例模式。
由於我以前是做java開發的,在使用單例模式的時候,首先想到的想用餓漢式,然後發現在PHP中,有這樣一個特性:因為PHP不支援在類定義時給類的成員變數賦予非基本類型的值。如運算式,new操作等等。所以了餓漢式這個就不行了。轉而想要確保這個單例模式的原子性,發現PHP中也沒有像JAVA中的安全執行緒問題。嘿嘿,你說PHP好不好?那麼OK接下來就試試PHP的懶漢式單例模式了。
先不說,我先上我第一個版本的單例模式代碼:
// 定義私人靜態變數.此種方式為:懶漢式單例(PHP中只有這種方式) private static $instance = null; // 私人化構成方法 private function __construct(){ } // 提供擷取執行個體的公用方法 public static function getInstance(){ if(!(self::$instance instanceof self)){ self::$instance = new self(); } return self::$instance; } // 私人__clone方法,禁止複製對象 private function __clone(){ }
OK,這段代碼看起很完美了,有注釋,有格式的,沒什麼問題了吧。但是當我在使用的過程中,我發現了一下問題
我的A類是單例模式的,然後我的B類繼承自A類,然後我調用如下方法:
$a = A::getInstance();$b = B::getInstance();var_dump($a === $b);
輸出的結果是:
bool(true)
這個輸出結果是什麼意思呢?也就是說:B繼承自A後,我本意是B也變成單例模式,那麼A、B只是繼承管理,他們的對象不應該相等,而現在兩個的對象完全一樣了,只能說明:通過
$b = B::getInstance();
得到的對象,還是是A類的對象,那這是怎麼回事?
問題出在self上,self的引用是在類被定義時就決定的,也就是說,繼承了B的A,他的self引用仍然指向A。為瞭解決這個問題,在PHP 5.3中引入了後期靜態繫結的特性。簡單說是通過static關鍵字來訪問靜態方法或者變數,與self不同,static的引用是由運行時決定。於是簡單改寫一下我們的代碼,讓單例模式可以複用。
class C{ protected static $_instance = null; protected function __construct(){ } protected function __clone(){ } public function getInstance(){ if (static::$_instance === null) { static::$_instance = new static; } return static::$_instance; } }class D extends C{ protected static $_instance = null;}$c = C::getInstance();$d = D::getInstance();var_dump($c === $d);
這是時候的輸出就會變成:
bool(false)
然後就可以達到,只要繼承這個單例模式,那麼它的子類也是單例模式。就可以達到完美複用的作用,不用每次需要單例模式都去寫那麼多重複代碼了。注意上面的方法只有在PHP 5.3中才能使用,對於之前版本的PHP,還是老老實實為每個單例類寫一個getInstance()方法吧。
API開發第三篇:PHP的設計模式之完美的單例模式