28

私は Web アプリ フレームワークで作業しており、その一部は多数のサービスで構成されており、すべてシングルトンとして実装されています。それらはすべて、シングルトンの動作が実装されている Service クラスを拡張し、次のようになります。

class Service {
    protected static $instance;

    public function Service() {
        if (isset(self::$instance)) {
            throw new Exception('Please use Service::getInstance.');
        }
    }

    public static function &getInstance() {
        if (empty(self::$instance)) {
            self::$instance = new self();
        }
        return self::$instance;
    }
}

さて、次のように実装された FileService というクラスがあるとします。

class FileService extends Service {
    // Lots of neat stuff in here
}

... FileService::getInstance() を呼び出しても、必要なように FileService インスタンスは生成されませんが、Service インスタンスが生成されます。ここでの問題は、Service コンストラクターで使用される「self」キーワードにあると思います。

ここで私が望むものを達成する他の方法はありますか? シングルトン コードは数行しかありませんが、できる限りコードの冗長性を避けたいと考えています。

4

6 に答える 6

61

コード:

abstract class Singleton
{
    protected function __construct()
    {
    }

    final public static function getInstance()
    {
        static $instances = array();

        $calledClass = get_called_class();

        if (!isset($instances[$calledClass]))
        {
            $instances[$calledClass] = new $calledClass();
        }

        return $instances[$calledClass];
    }

    final private function __clone()
    {
    }
}

class FileService extends Singleton
{
    // Lots of neat stuff in here
}

$fs = FileService::getInstance();

PHP < 5.3 を使用している場合は、これも追加します。

// get_called_class() is only in PHP >= 5.3.
if (!function_exists('get_called_class'))
{
    function get_called_class()
    {
        $bt = debug_backtrace();
        $l = 0;
        do
        {
            $l++;
            $lines = file($bt[$l]['file']);
            $callerLine = $lines[$bt[$l]['line']-1];
            preg_match('/([a-zA-Z0-9\_]+)::'.$bt[$l]['function'].'/', $callerLine, $matches);
        } while ($matches[1] === 'parent' && $matches[1]);

        return $matches[1];
    }
}
于 2010-06-27T02:32:52.290 に答える
9

5.3 のクラスでもっと注意を払っていたら、自分で解決する方法を知っていたでしょう。PHP 5.3 の新しい遅延静的バインディング機能を使用すると、Coronatus の命題は次のように単純化できると思います。

class Singleton {
    protected static $instance;

    protected function __construct() { }

    final public static function getInstance() {
        if (!isset(static::$instance)) {
            static::$instance = new static();
        }

        return static::$instance;
    }

    final private function __clone() { }
}

私はそれを試してみましたが、それは魅力のように機能します。ただし、5.3 より前の場合は、まったく別の話です。

于 2010-06-29T18:39:15.490 に答える
3

これはヨハンの答えで修正されました。PHP 5.3+

abstract class Singleton
{
    protected function __construct() {}
    final protected function __clone() {}

    final public static function getInstance()
    {
        static $instance = null;

        if (null === $instance)
        {
            $instance = new static();
        }

        return $instance;
    }
}
于 2017-11-21T23:58:56.653 に答える