絶品ゆどうふのタレ

ふと気づいたことを綴るだけのメモ

PHP5.3で継承して使うSingletonをちゃんとやる

発端

02:51:51 (sotarok) で, hoge_klass::get_instance() も,同じように動くようにしたい,でも,hoge_klass には, get_instance を再実装したくないよね

略しすぎてなんだか分からない人のために言っとくと、まぁSingletonの実装ってメンドいから継承したいよねと。


昔、Objective-Cでもそれやったけど
継承して使えるSingletonクラス - ゆどうふろぐ
PHP5.3で遅延静的束縛ができたから、継承できるSingletonを実装できるようになったから。
まぁあちこちサンプルあるけど、なんかcloneとかconstructとかちゃんとやって無いし。


で、まぁノリで書いてみたらfinalとかがcloneやconsructに付けられるという事実が分かって*1、なんか思ったよりきちんと重複を排除できる感じで、継承して使えるSingletonが書けたのでブログに乗っけとく。

<?php
class Singleton
{
  private static $instance = array();

  final private function __construct()
  {
    if (isset(self::$instance[get_called_class()]))
    {
      throw new Exception("複数作るなんてできないよ");
    }
    static::initialize();
  }

  protected function initialize()
  {
    # ここでコンストラクタの初期化実装
  }

  final public static function getInstance()
  {
    $class = get_called_class();
    if (!isset(self::$instance[$class]))
    {
      self::$instance[$class] = new static();
    }
    return self::$instance[$class];
  }

  final private function __clone()
  {
    throw new Exception("cloneなんてできないよ");
  }
}

試しに継承:

<?php
require_once "singleton.php";

class Hoge extends Singleton
{
  public $foo;
  public $hoge;

  protected function initialize()
  {
    $this->foo = "bar";
  }
}

class Huga extends Singleton
{
}

$aaa = Singleton::getInstance();
$bbb = Hoge::getInstance();
$ccc = Hoge::getInstance();
$ddd = Huga ::getInstance();

$bbb->hoge = "huga";

var_dump($aaa);
var_dump($bbb);
var_dump($ccc);
var_dump($ddd);

結果:

object(Singleton)#1 (0) {
}
object(Hoge)#2 (2) {
  ["foo"]=>
  string(3) "bar"
  ["hoge"]=>
  string(4) "huga"
}
object(Hoge)#2 (2) {
  ["foo"]=>
  string(3) "bar"
  ["hoge"]=>
  string(4) "huga"
}
object(Huga)#3 (0) {
}

もちろんcloneもnewも、ちゃんとNGでます。
継承してconstructやcloneを実装できちゃう!なんてこともないです。


素敵ですね。
でっていう。

*1:すいません今まで知りませんでした