Singleton php примеры. Singleton в PHP на примере подключения к MySQL. Когда стоит использовать Singleton

  • 20.06.2020

Начинающие программисты, столкнувшись с ООП, обязтельно натыкаются на необходимость использования (ну или хотя бы понимания) шаблонов проектирования. И это многих пугает. Мало того, что сама парадигма достаточно сложна для понимания, так еще и паттерны какие-то. И хотя они как раз и придуманы для облегчения использования парадигмы, на первых порах играют как раз обратную роль. А всё из-за того, что те, кто придумывают паттерны, давно в ООП как рыба в воде, соответственно и объясняют их со своей колокольни. И получается замкнутый круг. Не зная паттернов сложно грамотно использовать ООП парадигму, однако не зная ООП сложно понять эти самые паттерны.

А все как обычно крайне просто. Нужно только создать необходимую ассоциацию, как все встанет на свои места.

Вот сейчас я попробую объяснить пару шаблонов простым русским языком. Может что-либо и получится.

Начнем с синглтона. Singleton переводится с английского как "одиночка". Но это так, ремарка. Теперь перенесемся в реальную жизнь.

Допустим вы хотите получить водительское удостоверение (права). Вы должны пройти соответствующее обучение и сдать экзамены в госавтоинспекции. И когда вы это сделаете, вам выдаются права. Это не просто корочка, а право на управление транспортым средством.

А теперь представьте, что вы эту корочку ненароком потеряли. Ну или она пришла в негодность, да мало ли. Вам не нужно снова учиться, не нужно сдавать экзамены. Это уже все есть пожизненно. Вам нужно просто придти в ГАИ и получить дубликат. Тоесть результат когда то произведенных вами действий.

Это и есть суть "синглтон", тоесть "один раз". Необходимые для получения прав действия (обучение и сдача экзаменов) мы производим один раз в жизни. А результатом можем пользоваться сколь угодно мгого раз.

Теперь дальше, ближе к программированию. Вообще этот паттерн не являются паттерном ООП, как многие ошибочно полагают. Это паттерны проектировния или design patterns. Их можно использовать и помимо ООП и даже классов, в обычных функциях. Вот, чтобы было понятнее, с них и начнем. Вот допустим такая простенькая функция:

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15

Function mySingleton ()
{
$time = microtime (true );

Return $time ;
}

Echo mySingleton ();
echo "
" ;
sleep (1 );
echo mySingleton ();

Если зпустить этот код, второй результат будет на секунду отличаться от первого. Ну это и понятно, не требует пояснений. Но вот если сделать так:

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18

Function mySingleton ()
{
static $time ;

If(empty($time ))
$time = microtime (true );

Return $time ;
}

Echo mySingleton ();
echo "
" ;
sleep (1 );
echo mySingleton ();

то сколько бы раз теперь мы бы не запускали функцию, результат будет одинаковый. Тот, который был вычислен при первом обращении. Вот это и есть синглтон во всей своей красе, правда очень примитивный.

Ну а теперь непосредственно в ООП. Не будем уходить от темы, просто обернем первую функцию в класс:

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22

class mySingleton
{
public $time ;


{
$this -> time = microtime (true );
}
}

$obj = new mySingleton ();
echo $obj -> time ;

Echo "
" ;
sleep (1 );

$obj = new mySingleton ();
echo $obj -> time ;

И тут, каждый раз, когда мы создем объект, свойство $time будет принимать новое значение. Это иногда очень вредно, особенно при коннекте к базе данных. Если его поместить в конструктор, то подключение к бд будет происходить при каждой инициализации, а для скрипта обычно этого бывает достаточно сделать только единожды.

Но вернемся к нашим бранам. Как же нам сделать синглтон из класса? Чтобы получать только один объект, сколько бы раз мы к нему не обращались. Такая возможнсть появилась вместе с появлением статических классов. Вернее с возможностью использовать два в одном. Обращться к классу, как к таковому (статика) и создвать на его основе объекты. Вот мы сейчас заставим наш класс инициализировать и возвращать собственный объект:

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26

Class mySingleton
{
public $time ;


{
return new self ;
}

Public function __construct ()
{
$this -> time = microtime (true );
}
}


echo $obj -> time ;

Echo "
" ;
sleep (1 );

$obj = mySingleton :: getInstance ();
echo $obj -> time ;

Обратите внимание, снаружи мы получили объект без конструкции new , обртившись к статическому методу класса через двойное двоеточие. Однако объектом он от этого быть не перестал. Хотя и результат не изменился.

Однако мы же знаем, что объект можно легко поместить в переменную. И тем более в свойство. Ну а его можно объявить статичным. И вот мы плавно подошли к реализации синглтона. Делаем по образу и подобию нашей второй функции:

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32

class mySingleton
{
public $time ;
static private $instance ;

Public static function getInstance ()
{

Return self :: $instance ;
}

Public function __construct ()
{
$this -> time = microtime (true );
}
}

$obj = mySingleton :: getInstance ();
echo $obj -> time ;

Echo "
" ;
sleep (1 );

$obj = mySingleton :: getInstance ();
echo $obj -> time ;

Вот и все, посмотрите на результат. Мы имеем то, что было вычислено при инициализации первого объекта. Еще бы, ведь это он и есть. Теперь один единственный, сколько бы раз мы его не дергали. Однако он будет так себя вести только при условии, что мы будем получать объект через статический метод. Но ведь есть еще возможность создать объект и с помощью конструкции new . А значит все наши труды насмарку. Так вот, чтобы загарантироваться от подобных казусов, нужно объявить конструктор приватным. Тогда конструкция new вне клаасса вызовет фатальную ошибку. Ну и на всякий случай запретим клонирование от греха подальше.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34

class mySingleton
{
public $time ;
static private $instance ;

Public static function getInstance ()
{
if(empty(self :: $instance ))
self :: $instance = new self ;

Return self :: $instance ;
}

Private function __construct ()
{
$this -> time = microtime (true );
}

Private function __clone (){}
}

$obj = mySingleton :: getInstance ();
echo $obj -> time ;

Echo "
" ;
sleep (1 );

$obj = mySingleton :: getInstance ();
echo $obj -> time ;

Ну вот и все, мы имеем одну из самых распространенных реализаций паттерна Singletone

Что можно добавить. Использовать этот паттерн нужно с большой осторожностью, у него есть несколько недостатков. Он сродни глобальной переменной, он нарушает принцип SRP ну и так далее. Это тема отдельной публикации.

Но иногда, особенно при упомянутой организации коннекта к серверу СУБД, бывает очень даже полезен.

Просто не забывайте принцип KISS и используйте все в меру.

В следующий раз постараюсь рассказать еще несколько "знаменитых" паттернов, а пока всё)))

Введение

Singleton – один из самых простых шаблонов для понимания. Основное назначение – гарантировать существование только одно экземпляра класса. Причиной обычно является следующее: требуется только один объект исходного класса и Вам необходимо, что бы объект был доступен в любом месте приложения, т.е. глобальный доступ.

В качестве примера может служить класс для хранения установочных параметров(Settings). Settings class – хороший пример шаблона Singleton, потому что его данные не измены (единственный путь изменения установочных параметров это редактирование файла установочных параметров) и часто используются в различных частях приложения. Кроме того, создание новых объектов класса Settings, где это необходимо, требует ресурсы, что расточительно, т.к. объекты будут идентичны.

Определение

Шаблон Singleton предполагает наличие статического метода для создания экземпляра класса, при обращении к которому возвращается ссылка на оригинальный объект.

Пример для PHP5

Пример для PHP5(без реализации конкретных методов класса Settings)
class Settings {
private $settings = array();
private static $_instance = null;
private function __construct() {
// приватный конструктор ограничивает реализацию getInstance ()
}
protected function __clone() {
// ограничивает клонирование объекта
}
static public function getInstance() {
if(is_null(self::$_instance))
{
self::$_instance = new self();
}
return self::$_instance;
}
public function import() {
// ...
}
public function get() {
// ...
}
}

Реализация шаблона Singleton

Ключoм реализации шаблона Singleton является статическая переменная, переменная чье значение остается неизменным при исполнении за ее приделами. Это позволяет сохранить объект оригинальным между вызовами статического метода Settings::getInstance(), и возвратить ссылку на него при каждом последующем вызове метода.
Имейте так же в виду, что конструктор, как правило, приватный. Что бы обеспечить использование всегда только одного объекта Settings мы должны ограничить доступ к конструктору, что бы при попытке создания нового объекта возникала ошибка. Так же следует иметь в виду, что данные ограничения не возможны в PHP4.

Singleton Pattern (single - единственный [англ.] ton - мода, стиль [англ.]) - один из наиболее известных шаблонов проектирования. Почти в любой объктно-ориентированной программе обычно существует один-два объекта, которые инициализируются в начале, и используются на всем протяжении работы приложения. Нет нужды каждый раз создавать объект класса, достаточно создать один экземпляр класса, в начале работы программы, и пользоваться им.

В РНР5 singleton определяется так

Пример использования

doAction(); ?>

Преимущества данного метода очевидны:

  1. Мы используем ссылки на один и тот же экземпляр класса в разных частях проекта. Таким образом не нужно создавать новый объект каждый раз когда мы хотим воспользоваться каким-то методом - просто пользуемся ссылкой.
  2. Теперь не нужно передавать объект как аргумент, чтоб все части программы были «в курсе» о текущем состоянии объекта. Все ссылки указывают на один объект.

PHP 5.3

Начиная с PHP 5.3.0 была добавлена возможность , благодаря которой этот паттерн можно реализовать в виде абстрактного класса:

Удачного вам кодинга!

Введение

Singleton – один из самых простых шаблонов для понимания. Основное назначение – гарантировать существование только одно экземпляра класса. Причиной обычно является следующее: требуется только один объект исходного класса и Вам необходимо, что бы объект был доступен в любом месте приложения, т.е. глобальный доступ.

В качестве примера может служить класс для хранения установочных параметров(Settings). Settings class – хороший пример шаблона Singleton, потому что его данные не измены (единственный путь изменения установочных параметров это редактирование файла установочных параметров) и часто используются в различных частях приложения. Кроме того, создание новых объектов класса Settings, где это необходимо, требует ресурсы, что расточительно, т.к. объекты будут идентичны.

Определение

Шаблон Singleton предполагает наличие статического метода для создания экземпляра класса, при обращении к которому возвращается ссылка на оригинальный объект.

Пример для PHP5

Пример для PHP5(без реализации конкретных методов класса Settings)
class Settings {
private $settings = array();
private static $_instance = null;
private function __construct() {
// приватный конструктор ограничивает реализацию getInstance ()
}
protected function __clone() {
// ограничивает клонирование объекта
}
static public function getInstance() {
if(is_null(self::$_instance))
{
self::$_instance = new self();
}
return self::$_instance;
}
public function import() {
// ...
}
public function get() {
// ...
}
}

Реализация шаблона Singleton

Ключoм реализации шаблона Singleton является статическая переменная, переменная чье значение остается неизменным при исполнении за ее приделами. Это позволяет сохранить объект оригинальным между вызовами статического метода Settings::getInstance(), и возвратить ссылку на него при каждом последующем вызове метода.
Имейте так же в виду, что конструктор, как правило, приватный. Что бы обеспечить использование всегда только одного объекта Settings мы должны ограничить доступ к конструктору, что бы при попытке создания нового объекта возникала ошибка. Так же следует иметь в виду, что данные ограничения не возможны в PHP4.

Сегодня я хочу разобрать шаблон проектирования "одиночка" , который очень часто используется в объектно-ориентированном программировании.

Шаблон проектирования "Одиночка" или Pattern Singleton нужен для того, чтобы у нас не было много однотипных объектов, а всегда использовался только один. В качестве примера можно привести класс для работы с базой данных.

Class DB {
protected $db;

Public function __construct() {
$this->
}

Public function get() {}
public function set() {}
public function del() {}
}

$db1 = new DB();
$db2 = new DB();

У нас уже 2 объекта $db1 и $db2 , а потом кто-нибудь, не зная, что уже есть такой объект, создаст третий и т.д. Это очень плохо сказывается на производительности и читаемости кода, а в нашем случае может произойти сбой, т.к. на хостинге ограниченное количество подключений к базе данных.

Чтобы решить эту проблему, и был придуман паттерн singleton .

Class DB {
protected $db;
static private $instance = null;

Private function __construct() {
$this->db = new Mysqli($host, $user, $pass, $database);
}

Private function __clone() {}

Static function getInstance() {
if(self::$instance == null) {
self::$instance = new self();
}
return self::$instance;
}
}

$db = new DB(); // ошибка

$db = DB::getInstance();
$db2 = DB::getInstance();
$db3 = DB::getInstance();

Чтобы создать объект обычным способом было нельзя, мы делаем наш конструктор приватным , но также не забываем и про то, что объекты могут клонироваться и закрываем также метод __clone . Дальше мы создаём статическое свойство $instance , которое по умолчанию равно null . Теперь создаём статический метод getInstance() , который проверяет, равно ли наше статическое свойство null ? Если да, то мы создаём экземпляр нашего объекта и возвращаем его, а если же нет, то просто возвращаем его. Таким образом, у нас всегда будет один и тот же экземпляр, сколько бы мы их не создавали. Использовать его очень просто: присваиваем переменной значение, которое возвращает статический метод getInstance() , класса DB , а дальше работаем, как и с обычным объектом.