Pull to refresh

Практическая реализация паттерна Singleton на PHP

Практически в каждом объектно-ориентированном приложении есть классы, экземпляры которых мы создаём по несколько раз за время выполнения скрипта, например, подключение к базе данных.

Но зачем мы делаем такие нагрузочные для PHP операции? Ведь если подключение к БД было установлено, зачем его закрывать, а через мгновение снова открывать? В неопытных программистов такие операции происходят по несколько раз за один запрос. В идеале я вижу такой сценарий исполнения скрипта:

1. Создали подключение к базе данных;
2. Использовали его во всех нужных местах нашего приложения;
3. Закрыли соединение с базой данных.

Ваше приложение просто может вновь и вновь использовать экземпляр уже созданного класса. А как же не допустить создание новых экземпляров класса, если например, другой класс, не знает было ли до этого установлено соединение с БД, которую он использует? Если соединение было установлено, то где его «взять»? Сегодня я расскажу Вам как грамотно и профессионально решить подобную задачу.

Решение

Конечно, Вы можете сказать мне, что решение уже есть и выдумывать ничего не надо – глобальные переменные. Действительно, Вы вполне сможете использовать глобальные переменные для решения подобных проблем, но их использование неудобное и не грамотное решение.

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

Когда Вы хотите быть уверенными, что создается лишь один экземпляр конкретного класса в Вашем приложении, Вам необходимо использовать т.н. «шаблон проектирования» Singleton(Одиночка). Суть работы класса, который реализует данный паттерн, очень проста:

1. Закрываем доступ к функциям __construct() и __clone(), используя ключевое слово private;
2. Объявляем статическую защищенную переменную $_instance нашего класса;
3. Создаём «public static» метод класса getInstance(), который будет возвращать нам экземпляр класса.

Как Вы можете сами увидеть, реализовать шаблон проектирования Singleton очень просто. Нужно только хорошо знать объектно-ориентированное программирование, чтобы умело оперировать уровнем доступа к функциям и переменным класса, дабы защитить их от ненормативного использования.

Ниже приведен пример класса, который реализует паттерн Singleton:

<?php

/**
* Простой пример реализации паттерна Singleton
*
* @name SingletonTest
* @author Andrew Vasiliev (illusive [at] meta [dot] ua)
*/
class SingletonTest
{
/**
* Статическая переменная, в которой мы
* будем хранить экземпляр класса
*
* @var SingletonTest
*/
protected static $_instance;

/**
* Закрываем доступ к функции вне класса.
* Паттерн Singleton не допускает вызов
* этой функции вне класса
*
*/
private function __construct(){
/**
* При этом в функцию можно вписать
* свой код инициализации. Также можно
* использовать деструктор класса.
* Эти функции работают по прежднему,
* только не доступны вне класса
*/
}

/**
* Закрываем доступ к функции вне класса.
* Паттерн Singleton не допускает вызов
* этой функции вне класса
*
*/
private function __clone(){
}

/**
* Статическая функция, которая возвращает
* экземпляр класса или создает новый при
* необходимости
*
* @return SingletonTest
*/
public static function getInstance() {
// проверяем актуальность экземпляра
if (null === self::$_instance) {
// создаем новый экземпляр
self::$_instance = new self();
}
// возвращаем созданный или существующий экземпляр
return self::$_instance;
}
}

?>


Давайте разберём пошагово весь написанный код. Вначале кода мы объявляем класс SingletonTest. В объявленном классе создаём защищенную статическую переменную $_instance, в которой мы храним экземпляр класса. Далее делаем невозможным вызов функций __construct() и __clone() вне класса (т.е. не можно будет применить к классу оператор new).

Следующий шаг – дело техники. Функция getInstance(). Данная функция объявлена как статическая и общедоступная, поэтому мы можем вызывать её, даже не создавая экземпляр класса. Функция проверяет, есть ли у нас уже созданный экземпляр класса. Если есть – возвращает его, а если нет – создаёт новый экземпляр, сохраняя его в статической переменной, и потом возвращает его.

При этом конструктор и деструктор класса выполняются по одному разу, а это очень удобно использовать в своих нуждах (напр. закрыть/открыть файл, подключить/отключить БД и т.д.).

Делаем выводы

Итак, у нас есть изящное решение и если его мы сможем использовать правильно, то сможем добиться успеха.
Tags:
Hubs:
You can’t comment this publication because its author is not yet a full member of the community. You will be able to contact the author only after he or she has been invited by someone in the community. Until then, author’s username will be hidden by an alias.