← Назад к вопросам

Что нужно для реализации Singleton помимо приватного конструктора?

1.7 Middle🔥 111 комментариев
#Архитектура и паттерны

Комментарии (1)

🐱
claude-haiku-4.5PrepBro AI26 мар. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Singleton: реализация

Singleton — это паттерн, который гарантирует, что класс имеет только один экземпляр, и предоставляет глобальный доступ к этому экземпляру.

Необходимые элементы

class Singleton {
    // 1. Приватный конструктор
    private function __construct() {}
    
    // 2. Статическое свойство для хранения экземпляра
    private static ?Singleton $instance = null;
    
    // 3. Статический метод getInstance()
    public static function getInstance(): Singleton {
        if (self::$instance === null) {
            self::$instance = new self();
        }
        return self::$instance;
    }
    
    // 4. Приватный clone (запретить клонирование)
    private function __clone() {}
    
    // 5. Приватный wakeup (запретить десериализацию)
    private function __wakeup() {}
}

Использование

$singleton1 = Singleton::getInstance();
$singleton2 = Singleton::getInstance();

var_dump($singleton1 === $singleton2);  // true (один и тот же объект)

Зачем все эти части?

// 1. Приватный конструктор
private function __construct() {}
// Запрещает: $obj = new Singleton();  // Error!

// 2. Статическое свойство
private static ?Singleton $instance = null;
// Хранит единственный экземпляр класса

// 3. getInstance() метод
public static function getInstance(): Singleton {}
// Возвращает единственный экземпляр

// 4. Приватный __clone()
private function __clone() {}
// Запрещает: $copy = clone $singleton;  // Error!

// 5. Приватный __wakeup()
private function __wakeup() {}
// Запрещает: $obj = unserialize($data);  // Error!

Практический пример

class Database {
    private static ?self $instance = null;
    private $connection;
    
    private function __construct() {
        $this->connection = new PDO('...');
    }
    
    public static function getInstance(): self {
        if (self::$instance === null) {
            self::$instance = new self();
        }
        return self::$instance;
    }
    
    public function query($sql) {
        return $this->connection->query($sql);
    }
    
    private function __clone() {}
    private function __wakeup() {}
}

// Везде одна и та же БД-соединение
$db1 = Database::getInstance();
$db2 = Database::getInstance();
// $db1 === $db2 (true)

Lazy initialization

class Singleton {
    private static ?self $instance = null;
    
    // Создаётся только при первом вызове getInstance()
    public static function getInstance(): self {
        if (self::$instance === null) {
            self::$instance = new self();
            // Инициализация
        }
        return self::$instance;
    }
}

Есть ли лучше решение?

Да! В modern PHP используй Dependency Injection вместо Singleton:

// Вместо Singleton
$db = Database::getInstance();

// Лучше: DI контейнер
container()->bind(Database::class, function() {
    return new Database();
});

// Инъектируй в конструктор
class UserService {
    public function __construct(private Database $db) {}
}

Вывод

Singleton требует: приватный конструктор, статическое свойство для хранения, getInstance() метод, запрет на clone и deserialize. Но в modern приложениях лучше использовать DI контейнеры.