6
4

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

PHPでSingletonとFactoryの間のデザインパターンを考えてみる

6
Last updated at Posted at 2016-05-20

前提

先日はシングルトンのようで、ファクトリーパターンのような仕組みが必要になったのがきっかけです。
シングルトンの場合は、インスタンスが1度だけ生成されて、それ以降はStaticプロパティーを参照するのみですね。
ファクトリーパターンの場合は、インスタンスを生成し続ける目的で、場合によってはクラスの中で管理することもある。
その役割をミックスさせてパターンが必要になったので、備忘録代わりに書こうと思います。

1クラスにつき1インスタンスだけ生成させるパターン!

わかりにくいと思いますので、簡単なサンプルを載せいておきます。

sample.php
abstract class Singleton
{
	protected static $instance;

	protected function __construct(){}

	public static function get_instance()
	{
		if( static::$instance === null )
		{
			static::$instance = new static();
		}

		return static::$instance;
	}

	final function __clone()
	{
		throw new \Exception('Clone is not allowed against' . __CLASS__);
	}

	final function __wakeup()
	{
		throw new \Exception('Unserialize is not allowed against' . __CLASS__);
	}
}

class A extends Singleton {}

class B extends Singleton {}

A::get_instance();
B::get_instance();

// 結果:両方ともAクラスのインスタンスを返す

当然、両方のインスタンスはAクラスのものになります。これはシングルトンの正常動作ですね。
しかし、今回は1クラスにつき1つまでのインスタンスを生成したいので、下記のように変更します。

sample.php
abstract class Singleton_Factory
{
	protected static $instances = array();

	protected function __construct(){}

	public static function get_instance()
	{
		$called_cl = get_called_class();

		if( ! isset(static::$instances[ $called_cl ]) )
		{
			static::$instances[ $called_cl ] = new static();
		}

		return static::$instances[ $called_cl ];
	}

	final function __clone()
	{
		throw new \Exception('Clone is not allowed against' . __CLASS__);
	}

	final function __wakeup()
	{
		throw new \Exception('Unserialize is not allowed against' . __CLASS__);
	}
}

各クラスのインスタンスをStaticプロパティーで管理して、1つ以上は作らせない仕組みですね。
そもそもインスタンスを1つに制限させる理由は、使用するメモリを減らすことと、不具合を防ぐためですね。
Wordpressを例にすると、下記のようなコードをプラグインでよく見かけます。

sample-plugin.php
class Sample_Plugin
{
	public function __construct()
	{
		add_action("init", array(&$this, "init"));
	}

	public function init()
	{
		echo "do something here";
	}
}

new Sample_Plugin();

よく考えると、このクラスは1度しか初期化されちゃいけないんですよね。
なぜなら、initフックが二重で登録され、initメソッドが複数回呼ばれてしまうからです。
プラグインの中であれば製作者だけの問題なのですが、配布するとなれば気をつけた方がいい気がします。

以上、使い道は少なそうですが、備忘録用に載せておきます。

6
4
2

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
6
4

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?