Паттерн Singleton
Часть раздела Объектно-ориентированное программирование путешествия по PHP на Coddy. Урок 71 из 91.
Singleton Pattern — это порождающий шаблон проектирования, который гарантирует, что у класса будет только один экземпляр на протяжении всего жизненного цикла вашего приложения. Он также предоставляет глобальную точку доступа к этому экземпляру.
Этот паттерн полезен, когда вам нужен ровно один объект для координации действий во всей системе, например подключения к базе данных, менеджера конфигурации или логгера. Создание нескольких экземпляров таких объектов привело бы к напрасному расходованию ресурсов или непоследовательному поведению.
Вот как реализовать Singleton в PHP:
<?php
class Database {
private static ?Database $instance = null;
private function __construct() {
// Приватный конструктор предотвращает прямое создание экземпляра
}
public static function getInstance(): Database {
if (self::$instance === null) {
self::$instance = new self();
}
return self::$instance;
}
public function query(string $sql): string {
return "Executing: $sql";
}
}
$db1 = Database::getInstance();
$db2 = Database::getInstance();
echo $db1 === $db2 ? "Same instance" : "Different instances";
Output:
Same instanceШаблон опирается на три ключевых элемента: private constructor, который prevents прямое использование new, статическое property, хранящее единственный instance, и статический method, который создаёт instance при первом вызове и returns его при последующих вызовах.
Чтобы сделать Singleton действительно неуязвимым, следует также предотвратить клонирование и десериализацию:
<?php
private function __clone() {}
public function __wakeup() {
throw new Exception("Cannot unserialize singleton");
}
Задание
ЛегкоДавайте создадим менеджер конфигурации с использованием паттерна Singleton. В реальных приложениях обычно нужен единый источник истины для параметров конфигурации: наличие нескольких объектов конфигурации может привести к непоследовательному поведению в разных частях системы.
Вы организуете код в двух файлах:
Config.php: создайте классConfig, реализующий паттерн Singleton. Ваш менеджер конфигурации должен:- Хранить настройки в свойстве private array
- Иметь private constructor, который initializes массив настроек как empty
- Предоставлять статический метод
getInstance(), который returns единственный instance - prevent cloning, сделав
__clone()private - Включать метод
set(string $key, string $value): voidдля сохранения настройки - Включать метод
get(string $key): ?string, который returns значение для key илиnull, если key не существует - Включать метод
getAll(): array, который returns все настройки
main.php: подключите файл Config. Вы получите два входных значения: key и значение.Получите instance Config и установите настройку по умолчанию с key
"app_name"и значением"MyApp".Получите вторую reference на instance Config (снова используя
getInstance()) и используйте её, чтобы установить другую настройку, используя key и значение из входных данных.Наконец, проверьте, что Singleton работает правильно:
- Выведите
"Same instance: true"или"Same instance: false"в зависимости от того, указывают ли обе reference на один и тот же объект (используйте===для сравнения) - Выведите
"Settings count: [count]", показывающее общее количество сохранённых настроек (используйтеcount()для результатаgetAll()) - Выведите
"App name: [value]", показывающее настройку app_name, retrieved через вторую reference
- Выведите
Это задание демонстрирует основное преимущество паттерна Singleton: независимо от того, сколько раз вы вызываете getInstance(), вы всегда получаете один и тот же объект, благодаря чему все части приложения используют одно и то же состояние конфигурации.
Попробуйте сами
<?php
require_once 'Config.php';
// Читать ввод
$key = trim(fgets(STDIN));
$value = trim(fgets(STDIN));
// TODO: Получить экземпляр Config и установить "app_name" в "MyApp"
// TODO: Получить вторую ссылку на Config, снова используя getInstance()
// TODO: Использовать вторую ссылку для установки настройки с помощью $key и $value из ввода
// TODO: Проверить, что Singleton работает:
// - Print "Same instance: true" or "Same instance: false" based on === comparison
// - Print "Settings count: [count]" showing total settings
// - Вывести "App name: [value]", показывая app_name, полученный через вторую ссылку
?>В этом уроке есть небольшой тест. Начните урок, чтобы ответить на вопросы и сохранить прогресс.
Все уроки раздела Объектно-ориентированное программирование
1Основы ООП
Внешние файлыВведение в ООПКлассы и объектыКлючевое слово $thisМетодыСвойстваКонструктор (__construct)Деструктор (__destruct)Повторение — простой калькулятор4Наследование
Основы наследованияКлючевое слово parent::Переопределение методовКлючевое слово finalАбстрактные классыПовторение — иерархия сотрудников7Инкапсуляция
Public, Protected, PrivateМодификаторы доступа подробноГеттеры и сеттерыСокрытие информацииПродвижение конструктора (8.0)Повторение — система учёта студентов2Пространства имён и автозагрузка
Введение в пространства имёнКлючевое слово useСтандарт автозагрузки PSR-4Автозагрузчик ComposerПовторение — структурированный проект5Интерфейсы и контракты
Введение в интерфейсыРеализация интерфейсовРеализация нескольких интерфейсовИнтерфейс и абстрактный классАннотация типов с интерфейсамиПовторение — калькулятор фигур8Магические методы
Введение в магические методы__toString и __debugInfo__get, __set, __isset, __unset__call и __callStatic__clone и клонирование объектов__serialize и __unserializeПовторение — пользовательская коллекция3Свойства классов
Свойства экземпляра и статические свойстваКонстанты в классахСтатические методы и свойстваПриватные и защищённые свойстваСвойства только для чтения (PHP 8.1)Повторение — менеджер банковского счёта6Полиморфизм
Повторение переопределения методовПолиморфизм через интерфейсыАннотации типов и объединённые типыПозднее статическое связываниеПовторение — обработчик платежей9Трейты
Введение в трейтыИспользование нескольких трейтовРазрешение конфликтов трейтовАбстрактные методы в трейтахТрейты и наследование12Паттерны проектирования, часть 1
Введение в паттерны проектированияПаттерн SingletonПаттерн FactoryПаттерн ObserverПаттерн StrategyПотренируйтесь самостоятельно: Онлайн-компилятор PHP