Паттерны проектирования в PHP 8: синглтон и мультитон

Я хочу поговорить о паттернах проектирования в php в нескольких следующих статьях. Мне очень нравится, как развивается язык, поэтому я буду приводить примеры из последних нововведений php 8.

Синглтон

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

Давайте посмотрим, как мы можем реализовать подключение к базе данных классов и ведение журнала с одним экземпляром во всех объектах:

class Singleton
{
    protected static self|null $instance = null;

    final private function __construct(){}
    final protected function __clone(){}
    final protected function __wakeup(){}

    public static function getInstance(): static
    {
        if (static::$instance === null) {
            static::$instance = new static;
        }

        return static::$instance;
    }
}

class Database extends Singleton
{
    public function connect()
    {
        // ...
    }
}

class Logger extends Singleton
{
    private $connection;

    public function settings($connection = null)
    {
        $this->connection = $connection ?? '/var/logs/filename.log';
    }

    public function error(string $message)
    {
        // ...
    }

    public function warn(string $message)
    {
        // ...
    }
}
Вход в полноэкранный режим Выход из полноэкранного режима

Теперь мы будем использовать логгер для записи логов в таблицу базы данных. Для этого нам понадобится подключение к базе данных и установка его методом settings:

$db = Database::getInstance();
$db->connect();

$logger = Logger::getInstance();
$logger->settings($db);
$logger->error('Something wrong');
Войти в полноэкранный режим Выйти из полноэкранного режима

Multiton

Но что если нам нужно больше одного экземпляра логгера, потому что некоторые сообщения нужно записывать в файл, некоторые отправлять по электронной почте? Или у нас могут быть другие причины. Для этого мы воспользуемся шаблоном Multiton. Multiton очень похож на предыдущий паттерн, но с массивом экземпляров класса.

class Multiton
{
    protected static array|null $instance = null;

    final private function __construct(){}
    final protected function __clone(){}
    final protected function __wakeup(){}

    public static function getInstance(int|string $key): self
    {
        if (!array_key_exists($key, self::$instance)) {
            self::$instance[$key] = new self;
        }

        return self::$instance[$key];
    }
}

class Logger extends Multiton
{
    private array $settings;

    public function setSettings(array $settings)
    {
        // ...
    }

    public function error(string $message)
    {
        // ...
    }

    public function warn(string $message)
    {
        // ...
    }
}
Вход в полноэкранный режим Выход из полноэкранного режима

Сделаем два логгера с разными настройками для сохранения логов в файлы и в базу данных. Я не буду подробно описывать установку настроек и запись в файл/базу данных, так как это не важно для паттерна.

$fileLogger = Logger::getInstance('file');
$fileLogger->setSettings([
    //...
]);
$fileLogger->error('Error text');

$dbLogger = Logger::getInstance('database');
$dbLogger->setSettings([
    //...
]);
$dbLogger->error('Error will write in Database');
Вход в полноэкранный режим Выход из полноэкранного режима

Оцените статью
devanswers.ru
Добавить комментарий