一言で言うと?
あるクラスが一回しかインスタンス化が出来ないようにし、そのインスタンスが唯一無二であることを担保する。(ひとつのインスタンスを使いまわす。)
どんなシチュエーションで使うの?
- 正直自分、絶対必要なシチュエーションがあんまりぴんと来てないです、、、
- とりあえず、一つのインスタンスを使い回す必要のある時?
実装
実装の概要
※わかりやすさ重視ですごく無理やり考えたSingletonパターンの実装ですので、本来のSingletonパターンの意図としては間違っているかもしれませんので悪しからず。
- Shibuyaクラスが存在する
- プロパティにcountryとprefectureを持つ(国名と都道府県)
- 国名と都道府県は不変(?)のものであり、インスタンス毎に冗長にならないので、singletonパターンで一つのインスタンスを使い回す。
サンプルコード
Singletonパターンなクラス
Shibuya.php
<?php
namespace App;
class Shibuya
{
// 国名
private $country;
// 都道府県
private $prefecture;
// 検証用ID
private $id;
/**
* 一つしか作らないインスタンス格納用変数
*
* Undocumented variable
*
* @var [type]
*/
private static $instance;
private function __construct()
{
$this->country = 'Japan';
$this->prefecture = 'Tokyo';
// ランダムな数字を生成し、検証用IDに
$this->id = rand(1000000, 2000000);
}
/**
* インスタンス取得
*
* Undocumented function
*
* @return void
*/
public static function getInstance(): Shibuya
{
// プロパティにインスタンスが格納されていなければ、新しく生成。すでにあればそれを返す。
if (empty(self::$instance)) {
self::$instance = new Shibuya();
echo 'インスタンスがまだ作られていなかった為、作成しました。' . "\n";
}
return self::$instance;
}
/**
* IDを取得
*
* Undocumented function
*
* @return void
*/
public function getId(): int
{
return $this->id;
}
/**
* インスタンスを複製しようとした際の例外処理
*
* Undocumented function
*
* @return void
*/
public final function __clone()
{
throw new \Exception(get_class($this) . 'のインスタンスは複製できません。' . "\n");
}
}
実行クラス
Singleton.php
<?php
namespace App;
use App\Shibuya;
require 'vendor/autoload.php';
// staticメソッドでインスタンス化
$singleton_1 = Shibuya::getInstance();
$singleton_2 = Shibuya::getInstance();
// 検証用ID取得
$id_1 = $singleton_1->getId();
$id_2 = $singleton_2->getId();
echo 'ID : ' . $id_1 . "\n";
echo 'ID : ' . $id_2 . "\n";
// 検証用IDの一致確認
if ($id_1 === $id_2) {
echo 'IDが一致しています。' . "\n";
}
// インスタンスの一致確認
if ($singleton_1 === $singleton_2) {
echo 'インスタンスが一致しています。' . "\n";
}
// 複製された時の確認
$singleton_3 = clone $singleton_1;
実行結果
インスタンスがまだ作られていなかった為、作成しました。
ID : 1168743
ID : 1168743
IDが一致しています。
インスタンスが一致しています。
PHP Fatal error: Uncaught Exception: App\Shibuyaのインスタンスは複製できません。
...省略
地味に気をつけたいポイント
- Singletonパターンクラスのコンストラクタをprivateに (これをしないとstaticメソッド経由無しにインスタンス化出来てしまうので)
- __cloneメソッドのオーバーライドの際に「final」をつける (これをしないとサブクラスでオーバーライドし、複製できてしまうので)
参考
PHPによるデザインパターン入門 - Singleton〜いくつ作るかを制限する
http://shimooka.hateblo.jp/entry/20141212/1418363981