27 сен 2020

Шаблон Singleton

#php, #patterns, #oop

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

Шаблон Singleton

А в чём же риски - может спросить начинающий программист? Самая главная проблема заключается в том, что мы не можем их контролировать. Это значит, что любой разработчик в команде может где-нибудь (любое место) в коде перезаписать значение глобальной переменной и вы об этом узнаете только тогда, когда программа начнет работать не так, как положено и к вам придет ваш начальник с "нездорового вида" лицом. А потом вы долго и в мыле будете искать место в коде, где ошибка...

Singleton в php

Чтобы реже сталкиваться с глобальными переменными был придуман шаблон Singleton. Он позволяет вызывать один и тот же объект в любом месте кода, не прибегая к ним.

    Давайте конкретно его опишем - пусть это будет объект настроек всего приложения:
  1. 1) Который может существовать лишь в единичном экземпляре.
  2. 2) Его можно получить в любом месте программы.
  3. 3) Не привязан к глобальной переменной.
  4. 4) Позволяет получить значение любой настройки по ключу.
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
<?php

class Settings {
    static private $instance;
    
    private $settings = [
        'db_host'     => 'localhost',
        'db_user'     => 'root',
        'db_password' => 'super-secret',
        'db_name'     => 'my-pleasure'
    ];
    
    private final function __construct()
    {
    }
    
    static public function getInstance()
    {
        if (is_null(static::$instance)) {
            static::$instance = new static();
        }
        return static::$instance;
    }
    
    public function getSetting($key)
    {
        return $this->settings[$key];
    }
}

Для того, чтобы решить первую задачу, нам надо контролировать процесс создания объекта, поэтому конструктор мы сделаем приватным. Теперь снаружи класса нельзя будет его вызвать. А чтобы ни один из наследников не мог переписать этот метод, мы добавим ключевое слово final - строка 13.

Также мы не хотим давать возможность изменять основные настройки во время выполнения программы, поэтому их тоже сделаем приватными - строка 6.

Получить объект Settings мы сможем в любом месте нашего приложения с помощью статического метода getInstacne(), при первом вызове он создаст экзмепляр объекта, сохранит его в приватном свойстве $instance и вернет, а при повторных вызовах будет просто возвращать ранее созданный объект, без повторной инициализации.

Мы успешно решили задачу и создали класс, который позволяет создавать только один экземпляр объекта. А доступ к настройкам будет выгядеть так:

1
2
3
<?php 
$dbHost = Settings::getInstance()->getSetting('db_host');
$dbName = Settings::getInstance()->getSetting('db_name');

Подведем итоги

Благодаря паттерну Singleton нам удалось избежать использования глобальных переменных и это значительно улучшило надежность кода. Однако злоупотреблять этим паттерном не стоит, если вы будете часто его использовать, то может возникнуть ситуация, когда слишком много частей вашего приложения будут зависеть от одного объекта. А это породит новые проблемы, о которых мы поговорим в следующих статьях.

Все статьи

© 2020-2021 Александр Пантелеев