PHPは一例モードで一番安全なやり方を実現します。


一般的な設計モードとしては、一例モードが広く使用されている。どのように一つの例を設計するのが一番いいですか?
私達は通常このように書きます。ネットで検索できる例も大部分がそうです。constructメソッドをプライベートに設定すると、このクラスは他の人に実装されないことが保証されます。しかし、この書き方で明らかな問題は、コードが多重化されないことである。例えば、クラスA:

class A
{
    protected static $_instance = null;
    protected function __construct()
    {
        //disallow new instance
    }
    protected function __clone(){
        //disallow clone
    }
    public function getInstance()
    {
        if (self::$_instance === null) {
            self::$_instance = new self();
        }
        return self::$_instance;
    }
}
class B extends A
{
    protected static $_instance = null;
}

$a = A::getInstance();
$b = B::getInstance();
var_dump($a === $b);

上のコードは出力されます。

class B extends A
{
    protected static $_instance = null;
}

$a = A::getInstance();
$b = B::getInstance();
var_dump($a === $b);

問題はselfにあります。selfの引用はクラスが定義された時に決定されます。つまり、BのAを継承しています。彼のselfの引用は依然としてAを指しています。この問題を解決するために,PHP 5.3に後期静的バインディングの特性を導入した。簡単に言えば、staticキーワードで静的な方法や変数にアクセスすることで、selfとは違って、staticの引用は運転時に決定されます。そこで私たちのコードを簡単に書き換えて、一例のモードを多重化できるようにします。

bool(true)
以上のコード出力:

class C
{
    protected static $_instance = null;
    protected function __construct()
    {

    }
    protected function __clone()
    {
        //disallow clone
    }
    public function getInstance()
    {
        if (static::$_instance === null) {
            static::$_instance = new static;
        }
        return static::$_instance;
    }
}
class D extends C
{
    protected static $_instance = null;
}
$c = C::getInstance();
$d = D::getInstance();
var_dump($c === $d);

このようにして、簡単な継承と初期化を行います。instance変数は単例モードを実現できます。上の方法はPHP 5.3でしか使えませんので、前のバージョンのPHPに対しては、正直に各タイプにget Instanceを書いてください。
注意したいのは、PHPのシングルモデルはJavaのようなスレッドセキュリティの問題はないが、状態のあるクラスについては、単一の例モードを注意して使用することです。単例モードのクラスはPHP動作のライフサイクル全体を伴い、メモリに対してもオーバーヘッドとなります。