詳解PHP單例模式之繼承碰見的問題
<?php// 單例模式之繼承class Singleton{protected static $ins = null;private final function construct() { }protected final function clone() { }// public static function getIns() {// if(self::$ins === null){// self::$ins = new self();// }// return self::$ins;// }public static function getIns() {if(static::$ins === null){static::$ins = new static();}return static::$ins;}}class Child extends Singleton{// protected static $ins = null;}/*輸出結果為:bool(true) object(Singleton)#1 (0) { }問題:對象 $c1, $c2 竟然都是 Singleton 的執行個體 ???解決方案:將 getIns() 方法中關鍵字 self 替換為 static, 利用後期靜態繫結的特性*/$c1 = Child::getIns();$c2 = Child::getIns();var_dump($c1 === $c2); //truevar_dump($c1);// ------------------------------------------------------------------------// 另一個問題/*輸出結果為:bool(true) object(Child)#1 (0) { }問題:對象 $c3 竟然是 Child 的執行個體, 實際上應該是 Singleton 的執行個體 ???原因:因為 $ins 屬性是從父類 Singleton 繼承過來的, 當第一次調用 Child::getIns() 時, $ins = new Child() 當再次調用 Singleton::getIns() 時, $ins 已經被執行個體過了, 而且指向 Child 的執行個體, 所以此時 $c3 變成了 Child 的執行個體解決方案:在 Child 類中, 聲明自己專屬的 $ins 屬性*/$c3 = Singleton::getIns();var_dump($c1 === $c3);var_dump($c3);
後期靜態繫結的 getIns() 方法還會有一個問題:
若 Singleton 的 $ins 屬性被設定為 private 的,子類 Child 必須設定自己的 $ins 屬性,
因為 static::$ins 優先尋找子類自己的 $ins 屬性,但由於子類沒有聲明且父類的不能繼承,此時調用 Child::getIns()
方法便會報錯:
Fatal error: Cannot access property Child::$ins in D:\wamp\www\mycode\DesignPattern\Singleton.php on line 27
解決方案:
將父類 Singleton 的 $ins 屬性設定為 protected 的 或者 設定子類 Child 自己的 $ins 屬性