Singleton паттерн

Тренажер по PHP для пользователей с начальным уровнем подготовки.

Тренажер PHP

Паттерн "Одиночка" (Singleton) — один из самых известных порождающих паттернов проектирования. Его основная цель — гарантировать, что у класса будет только один-единственный экземпляр, и предоставить к нему глобальную точку доступа. Это бывает полезно для объектов, которые должны быть в системе в единственном экземпляре, например, для объекта подключения к базе данных, логгера или менеджера конфигурации.

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

Список тем

Компоненты паттерна Singleton

id: 39358_task1

Паттерн "Одиночка" состоит из нескольких ключевых элементов, каждый из которых выполняет свою строгую функцию. Сопоставьте компонент паттерна с его назначением, чтобы понять, как они вместе обеспечивают создание единственного экземпляра класса.

Сопоставьте строки в правой части с соответствующими строками в левой по порядковому номеру
private static $instance
private function __construct()
public static function getInstance()
private function __clone()
Запрещает прямое создание объекта через оператор `new`.
Предоставляет единый метод для получения экземпляра класса.
Запрещает клонирование существующего экземпляра.
Статическое свойство для хранения единственного экземпляра класса.
Сообщения
Проверить
Показать подсказку

Соберите основу Singleton из банка

id: 39358_task2

Перед вами — "скелет" класса Singleton. Используйте готовые токены из банка, чтобы правильно объявить статическое свойство для хранения экземпляра и сделать конструктор приватным. Это два первых шага к правильной реализации паттерна.

Нужно правильно расставить в пропуски предложенные варианты
class Logger
{
    input1S input2S $instance;

    input3S function input4S()
    {
        // Конструктор намеренно оставлен пустым
    }
}
private
static
public
__construct
$instance
getInstance
Сообщения
Проверить
Показать решение на 3 сек.
Показать подсказку

Реализация ленивой инициализации

id: 39358_task3

Дополните метод `getInstance()`. Он должен проверять, создан ли уже экземпляр класса. Если нет — создать его, если да — вернуть существующий. Этот механизм называется "ленивой" (или отложенной) инициализацией.

Заполните пропуски
class Connection
{
    private static $instance;

    private function __construct() {}
    private function __clone() {}

    public static function getInstance()
    {
        if (input1S === null) {
            input2S = new input3S();
        }
        
        return input4S;
    }
}
Сообщения
Проверить
Показать решение на 3 сек.
Показать подсказку

Найдите фатальную ошибку

id: 39358_task4

В этом коде допущена критическая ошибка, которая полностью нарушает принцип Singleton, позволяя создавать множество экземпляров класса. Найдите строку с ошибкой и исправьте ее так, чтобы конструктор стал недоступен извне.

Найдите ошибку и исправьте
class Settings {
    private static $instance;
 
    public function __construct() { // Создание объекта разрешено
        // ...
    }
 
    public static function getInstance() {
        if (self::$instance === null) {
            self::$instance = new self();
        }
        return self::$instance;
    }
}
 
$settings1 = new Settings(); // Это не должно работать!
$settings2 = new Settings();
Сообщения
Проверить
Показать решение на 3 сек.
Показать подсказку

Соберите полный класс Singleton

id: 39358_task5

Восстановите правильную структуру класса Singleton, перетащив строки из левой панели в правую. В банке есть лишние строки, которые содержат логические или синтаксические ошибки. Будьте внимательны и выбирайте только те, что формируют корректный и защищенный "Одиночку".

Перетяните в правильном порядке строки из одного блока в другой
private static $instance = null;
}
    private function __clone() { }
class ConfigReader {
    public static function getInstance() {
        if (self::$instance === null) { self::$instance = new self(); }
        return self::$instance;
    }
    public function __construct() { }
    private function __construct() { }
return new self();
private $instance;
Сообщения
Проверить
Показать решение на 3 сек.
Показать подсказку

Что покажет логгер?

id: 39358_task6

В коде создаются два объекта логгера через метод `getInstance()`. В первый объект добавляется сообщение, а затем второму объекту дается команда записать все сообщения. Что в итоге будет выведено на экран? Введите результат в поле.

Что должно получиться?
// Представьте, что класс Logger реализован как Singleton
// и имеет методы addMessage() и getMessages()

$log1 = Logger::getInstance();
$log1->addMessage("User logged in.");

$log2 = Logger::getInstance();
$log2->addMessage("Data saved.");

echo implode(" ", $log1->getMessages());
Сообщения
Проверить
Показать подсказку

Защита от десериализации

id: 39358_task7

Кроме клонирования, есть еще один способ "сломать" Singleton — через сериализацию и десериализацию. При десериализации может быть создан новый объект в обход `getInstance()`. Чтобы этого избежать, нужно "перехватить" магический метод `__wakeup`. В коде он есть, но с ошибкой. Исправьте ее, чтобы при попытке десериализации выбрасывалось исключение.

Найдите ошибку и исправьте
class CacheManager
{
    private static $instance;
    // ... пропущены __construct, __clone, getInstance
 
    private function __wakeup() // Неверный модификатор доступа
    {
        throw new \Exception("Cannot unserialize a singleton.");
    }
}
 
// Попытка обойти Singleton
$cache = CacheManager::getInstance();
$serialized = serialize($cache);
$newCache = unserialize($serialized); // Здесь должно быть исключение
Сообщения
Проверить
Показать решение на 3 сек.
Показать подсказку

Попытка прямого создания объекта

id: 39358_task8

Код пытается создать экземпляр класса `DBConnector` напрямую, используя оператор `new`. Что произойдет в результате выполнения этого кода, если класс `DBConnector` — это правильно реализованный Singleton? Выберите правильный вариант.

Выберите правильный вариант ответа
class DBConnector {
    private static $instance;
    private function __construct() { /* ... */ }
    public static function getInstance() { /* ... */ }
}

try {
    $db = new DBConnector();
    echo "Connection successful";
} catch (Error $e) {
    echo "Caught error: " . $e->getMessage();
}
Сообщения
Проверить
Показать подсказку
НайтиКурс.Ру