パターンは、最善の手順と良い設計を記述するための手段です。 パターンは、一般的なプログラム上の課題に柔軟な解決策を提供します。
Factory パターンにより、実行時にオブジェクトを初期化できるようになります。 オブジェクトを"製造する"ことに似ているため、これは Factory パターンと呼ばれています。 パラメータ化された Factory が、生成するクラス名を引数として受け取ります。
例1 パラメータ化された Factory メソッド
<?php
class Example
{
// パラメータ化された Factory メソッド
public static function factory($type)
{
if (include_once 'Drivers/' . $type . '.php') {
$classname = 'Driver_' . $type;
return new $classname;
} else {
throw new Exception('Driver not found');
}
}
}
?>
このメソッドをクラス内で定義することで、実行時に ロードされるドライバを作成できるようになります。 Example クラスが、データベース抽象化クラスで、 MySQL および SQLite ドライバをロードするとすると以下のように行うことができます。
<?php
// MySQL ドライバをロード
$mysql = Example::factory('MySQL');
// SQLite ドライバをロード
$sqlite = Example::factory('SQLite');
?>
Singleton は、あるクラスのインスタンスがひとつだけしかないことを保証し、 そのインスタンスに対してどこからでもアクセスできるようにします。 Singleton は、いわゆる "Gang of Four" による Creational Pattern のひとつです。
Singleton パターンを使って実装されることが多いのは、 データベースクラスやロガー、フロントコントローラ、あるいは リクエストやレスポンスを表すオブジェクトです。
例2 Singleton の例
<?php
class Example
{
private static $instance;
private $count = 0;
private function __construct()
{
}
public static function singleton()
{
if (!isset(self::$instance)) {
echo 'Creating new instance.';
$className = __CLASS__;
self::$instance = new $className;
}
return self::$instance;
}
public function increment()
{
return $this->count++;
}
public function __clone()
{
trigger_error('Clone is not allowed.', E_USER_ERROR);
}
public function __wakeup()
{
trigger_error('Unserializing is not allowed.', E_USER_ERROR);
}
}
?>
Singleton の挙動は、このようになります。
<?php
$singleton = Example::singleton(); // "Creating new instance." と表示
echo $singleton->increment(); // 0
echo $singleton->increment(); // 1
$singleton = Example::singleton(); // 既存のインスタンスを再利用
echo $singleton->increment(); // 2
echo $singleton->increment(); // 3
// これらはすべて Fatal エラーとなります
$singleton2 = new Example;
$singleton3 = clone $singleton;
$singleton4 = unserialize(serialize($singleton));
?>
Singleton パターンは、よく異論が出るパターンのひとつです。よくある批判は 「Singleton はアプリケーションにグローバルな状態を導入してしまうし、 Singleton とそれを使うクラスが密結合してしまう」というものです。 その結果、目に見えない依存関係や予期せぬ副作用が発生し、 テストや保守のしにくいコードが生まれてしまいます。
さらに、こんな批判もあります。 PHP のようなシェアードナッシング型のアーキテクチャで Singleton を使うのは無意味だ。 だって、いずれにせよオブジェクトはリクエスト内でだけ一意になるのだから。 それよりは、リクエストの開始時に Builder パターンや Factory パターンを使って協調オブジェクトグラフを作ったほうがずっと簡潔ですっきりする」。
Singleton は、"ソリッド" な OOP 設計規約やデメテルの法則にも違反します。 Singleton はシリアライズできません。そのサブタイプを作ることも (PHP 5.3 より前のバージョンでは) できないし、ガベージコレクションの対象にもなりません。そのインスタンスが Singleton の静的属性として格納されるからです。