読者です 読者をやめる 読者になる 読者になる

感謝のプログラミング 10000時間

たどり着いた結果(さき)は、感謝でした。

PHPでSingletonパターン。

<スポンサーリンク>

PHPオブジェクト指向をちゃんと身に付けるために、デザインパターンの勉強を始めました。

シングルトンは「どうしてもインスタンスを1つしか生成したくないとき」に使います。
インスタンスを1つしか生成したくない、逆に言うと1つしか生成できない状態にするのはなぜかというと、余計な処理コストを負いたくないからです。

もちろん、これは自分が注意して、「2つとしてインスタンスは作るまい」と誓えば、なんとかなるような問題かもしれません。
ですが、気持ちでカバーするのではなく、仕様として、あるクラスのインスタンスは1つしか存在しないことを保証する。

それがSingletonパターンです。

実際にSingletonパターンを見てみましょう。

<?php

class MySingleton {
        private static $instance;
        private $id;

        //コンストラクタ
        private function __construct() {
                $this->id = md5(date('r'));
        }

        //インスタンスを返す
        public static function getInstance() {
                if (!isset(self::$instance)) {
                        self::$instance = new MySingleton();
                }
                return self::$instance;
        }

        /**
         * このインスタンスの複製を許可しないようにする
         */
        public final function __clone() {
                throw new RuntimeException('クローンの作成は許可されていません' . get_class($this));
        }

        public function getId() {
                return $this->id;
        }
}

//クライアントの想定
$instance1 = MySingleton::getInstance();
$id1 = $instance1->getId();
echo "1つめのインスタンスのIDは:" . $id1, PHP_EOL;

$instance2 = MySingleton::getInstance();
$id2 = $instance2->getId();
echo "2つめに作ってみたインスタンスのIDも:" . $id2,PHP_EOL;

echo 'ふたつのIDは同じ?:' . ($id1 === $id2 ? 'true' : 'false'), PHP_EOL;

//cloneできないことを確認する
echo 'クローンを作ってみると・・・', PHP_EOL;
$instance1_clone = clone $instance1;

このプログラムを実行すると、以下のように表示されます。

1つめのインスタンスのIDは:5a61496847b179ee3db115835dff1489
2つめに作ってみたインスタンスのIDも:5a61496847b179ee3db115835dff1489
ふたつのIDは同じ?:true
クローンを作ってみると・・・

Fatal error: Uncaught exception 'RuntimeException' with message 'クローンの作成は許可されていませんMySingleton' in /home/sho322/php/singleton/Singleton.class.php:24
Stack trace:
#0 /home/sho322/php/singleton/Singleton.class.php(44): MySingleton->__clone()
#1 {main}
  thrown in /home/sho322/php/singleton/Singleton.class.php on line 24

「ふたつのIDは同じ?:true」の部分から、2つめのインスタンスを作ったつもりでも、1つ目に作ったものと同じインスタンスが返されていることがわかりますね。
つまり、インスタンスは一つしか作れない、ということです。

で、__cloneメソッドをオーバーライドして、インスタンスのクローンは作成できないようにしているので、クローンを作ろうとする例外が発生します。

これがPHPでSingletonパターンを作ってみるサンプルです。

この記事で使われた基礎知識

■self
selfキーワードは、クラスの内部で、「そのクラス自身」を指し示すキーワード」となる。
selfはダブルコロン(::)と一緒に使い、メソッドや定数、プロパティにアクセスする。

■static
staticを付けて宣言したメソッドやプロパティはインスタンス化されていなくても外部から直接呼び出すことができるようになる。
FactoryパターンやSingletonを使う時はstatic宣言が必要になる。

■this
オブジェクトのインスタンス化を行うと、クラスのメソッドで利用できる$thisという変数が自動的に定義される。
selfとの違いがよくわからなかったけど、たぶんthisはインスタンス化したオブジェクトのプロパティやメソッドにアクセスするために使う?
selfはオブジェクト自体にアクセスするとき、つまりクラス変数にアクセスするときに使うのかな?

■clone
オブジェクトの参照を渡すのではなく、複製したい場合はcloneキーワードを使う。

$cell = clone $saiyajin;

参考にした本

PHPによるデザインパターン入門

PHPによるデザインパターン入門

増刷されていない?のが不思議なくらいの良い本。
PHPデザインパターンが学べる唯一の日本語書籍。
図も適度にあってわかりやすく、説明も丁寧で理解しやすい。
結城浩さんのJavaデザインパターンと同じくらいいい本。
パーフェクトPHPで文法を調べながら読んだ。