Singleton (Единственный экземпляр)
Назначение:
Создание единственного экземпляра класса. В любой точке программы при работе с singleton вы будете работать с одним и тем же экземпляром класса.
Определение GoF?:
Убедится, что класс имеет только один экземпляр и предоставить глобальную точку доступа к нему.
Применяется в случае:
- Если существует необходимость создать единственный экземпляр класса
- В контексте PHP, в скриптах может применяться как замена глобальных переменных
Реализация:
Для реализации шаблона Singleton необходимо создать класс, имеющий статический аттрибут, ссылающиеся на экземпляр этого класса ($instance). Кроме того, класс должен содержать статический метод, возвращающий существующий экземпляр класса, если он уже был создан, или создающий новый экземпляр и сохраняющий его в аттрибут $instance. Кроме этого, необходимо объявить конструктор класса как private (для того чтобы гарантировать создание только одного экземпляра).
PHP4
Реализация для PHP4 в полной мере невозможна из-за отсутствия модификаторов области видимости (private, protected, public). Однако четко придерживаясь соглашений о кодировании использовать данный шаблон возможно.
Код может быть примерно таким:
class Singleton
{
/**
* @static
* @access public
* @example Для создания экземпляра этого класса используйте Singleton::getInstance(): $class = Singleton::getInstance();
* @example НЕ ИСПОЛЬЗУТЕ ОПРЕТОР new, СЛЕДУЮЩИЙ КОД НЕПРАВИЛЬНЫЙ: $class = new Singleton ( );
*/
function &getInstance ( )
{
static $instance = null;
if ( (isset($this)) && (get_class($this) == __CLASS__) )
trigger_error("Статический метод класса ".__CLASS__."::".__FUNCTION__."() вызван как не статический",E_USER_ERROR);
if ( is_null ( $instance ) )
{
$instance = array ( ); //дружно благодарим Андрея Сухачева (компания "Информ-Мобил")
$instance[0] = & new Singleton( null ); // за ценное замечание с использованием массива
}
return $instance[0];
}
/**
* @access private
* Конструктор без параметров (если вам нужны параметры добавьте их перед параметром $instance)
* Пытаемся обойти отсутсвие модификаторов области видимости в PHP4 используя параметр $instance
* Этот прием используем как защиту от случайных ошибок
*/
function Singleton ( $instance = "fake" )
{
if (!is_null($instance))
trigger_error("Нельзя использовать конструтор для создания класса Singleton.
Используйте статический метод getInstance ()",E_USER_ERROR);
//TODO: Добавьте основной код конструктора здесь
}
//Тут следует основной код класса
}
// ===========================================================================
// Другой вариант без массива подсказанного Андреем Сухачевым (компания "Информ-Мобил") 8-)
// -------------------------------------------------------------------------------------------------
/**
* @example Для создания экземпляра этого класса используйте
* @example Singleton::getInstance(): $object =& Singleton::getInstance();
* @example НЕ ИСПОЛЬЗУТЕ ОПРЕТОР new,
* @example СЛЕДУЮЩИЙ КОД НЕПРАВИЛЬНЫЙ: $object = new Singleton ( );
*/
class Singleton
{
function Singleton($directCall=true)
{
if ($directCall) {
trigger_error("Нельзя использовать конструтор для создания класса Singleton.
Используйте статический метод getInstance ()",E_USER_ERROR);
}
//TODO: Добавьте основной код конструктора здесь
}
function &getInstance()
{
static $instance;
if (!is_object($instance)) {
$instance = new Singleton(false);
}
return $instance;
}
}
PHP5
Для PHP5 реализация выглядит проще:
class Singleton
{
private static $instance = null;
public static function getInstance ( )
{
if ( is_null ( self::$instance ) )
{
self::$instance = new Singleton ( );
}
return self::$instance;
}
private function __construct( )
{
//TODO: Код конструктора здесь
}
private function __clone ( )
{
// Конструктор копирования нам не нужен
}
//Тут следует основной код класса
}
Для получения экземпляра класса Singleton в PHP4 используется следующая конструкция (поправка Бориса Безрукова aka Lovchy):
$Object = & Singleton::getInstance();
Для получения экземпляра класса Singleton в PHP5 используется следующая конструкция:
$Object = Singleton::getInstance();