Menu
Coddy logo textTech

Паттерн 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");
}
challenge icon

Задание

Легко

Давайте создадим менеджер конфигурации с использованием паттерна 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, полученный через вторую ссылку

?>
quiz iconПроверьте себя

В этом уроке есть небольшой тест. Начните урок, чтобы ответить на вопросы и сохранить прогресс.

Все уроки раздела Объектно-ориентированное программирование

Потренируйтесь самостоятельно: Онлайн-компилятор PHP