Расширение одиночных элементов в PHP

Я работаю в платформе веб-приложения, и часть ее состоит из многих сервисов, все реализованные как одиночные элементы. Они все расширяют Класс обслуживания, где одноэлементное поведение реализовано, выглядя примерно так:

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, как я хочу его к, но Сервисный экземпляр. Я предполагаю, что проблема вот "сам" ключевое слово, используемое в Сервисном конструкторе.

Там некоторый другой путь состоит в том, чтобы достигнуть того, что я хочу здесь? Одноэлементный код является только несколькими строками, но я все еще хотел бы избежать любого дублирования кода каждый раз, когда я могу.

25
задан hakre 10 June 2012 в 21:57
поделиться

2 ответа

Код:

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];
    }
}
55
ответ дан 28 November 2019 в 18:13
поделиться

Если бы я уделял больше внимания в классе 5.3, я бы знал, как решить эту проблему сам. Используя новую функцию позднего статического связывания в PHP 5.3, я считаю, что предложение Коронатуса можно упростить до следующего:

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() { }
}

Я попробовал это, и он работает как шарм. Однако Pre 5.3 - это совсем другая история.

8
ответ дан 28 November 2019 в 18:13
поделиться
Другие вопросы по тегам:

Похожие вопросы: