Ответ
Singleton гарантирует существование только одного экземпляра класса и предоставляет глобальную точку доступа к нему. В реальных проектах я использовал его для логгера или менеджера конфигурации, чтобы избежать дублирования ресурсов и состояния.
Пример: Логгер приложения В веб-приложении разные части системы (контроллеры, сервисы, middleware) должны писать логи в один и тот же файл или отправлять в одну и ту же внешнюю систему (например, Elasticsearch через Monolog). Создание нового экземпляра логгера для каждого вызова было бы избыточным и могло бы привести к конфликтам при записи в файл.
// app/Logging/AppLogger.php
class AppLogger
{
private static ?self $instance = null;
private MonologLogger $logger;
// Приватный конструктор предотвращает создание через `new`
private function __construct()
{
$this->logger = new MonologLogger('app');
$handler = new StreamHandler(storage_path('logs/app.log'), Level::Debug);
$this->logger->pushHandler($handler);
}
// Статический метод для получения единственного экземпляра
public static function getInstance(): self
{
if (self::$instance === null) {
self::$instance = new self();
}
return self::$instance;
}
// Публичные методы для логирования
public function info(string $message, array $context = []): void
{
$this->logger->info($message, $context);
}
public function error(string $message, array $context = []): void
{
$this->logger->error($message, $context);
}
}
// Использование в любом месте приложения
// app/Services/PaymentService.php
class PaymentService
{
public function process(Payment $payment): void
{
$logger = AppLogger::getInstance();
try {
// ... логика оплаты
$logger->info('Payment processed', ['payment_id' => $payment->id]);
} catch (Exception $e) {
$logger->error('Payment failed', ['error' => $e->getMessage()]);
throw $e;
}
}
}
Важно: В современных PHP-фреймворках (Laravel, Symfony) необходимость в «ручном» Singleton часто отпадает, так как контейнер внедрения зависимостей (DI Container) по умолчанию управляет сервисами в режиме singleton. Однако понимание паттерна важно для работы с legacy-кодом или при проектировании собственных библиотек.