LoginSignup
1
1

More than 3 years have passed since last update.

ざっくりとPHPで学ぶ!忙しい人のためのデザインパターン入門②Singletonパターン

Last updated at Posted at 2020-04-12

一言で言うと?

あるクラスが一回しかインスタンス化が出来ないようにし、そのインスタンスが唯一無二であることを担保する。(ひとつのインスタンスを使いまわす。)

どんなシチュエーションで使うの?

  • 正直自分、絶対必要なシチュエーションがあんまりぴんと来てないです、、、
  • とりあえず、一つのインスタンスを使い回す必要のある時?

実装

実装の概要

※わかりやすさ重視ですごく無理やり考えた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

1
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
1