» » Ломаем паттерн проектирования — Singleton в PHP

 

Ломаем паттерн проектирования — Singleton в PHP

Автор: admin от 5-05-2019, 11:05, посмотрело: 396

Одним прекрасным рабочим днём я писал unit-тесты для бизнес-логики на проекте, в котором работаю. Передо мною стояла задача инициализировать некоторые приватные свойства класса определёнными значениями.

интересную статью, в которой описано, как с помощью бибилотеки dg/bypass-finals можно замокать финальный класс. Этот вариант мне понравился и я попробовал его внедрить. К сожалению, у меня ничего не получилось, так как на проекте используется старая версия PHPUnit.



Поразмыслив, я вспомнил о классе Closure, а конкретно о его статическом методе bind(), который умеет внедрять анонимные функции в контекст нужного объекта какого-либо класса. Больше информации об этом можно найти в официальной документации. Поэтому я создал трейт, который использовал в своих тестах (может кому-то тоже будет полезен)



trait PrivatePropertySetterTrait
{
    protected function assignValue($object, string $attribute, $value)
    {
        $setter = function ($value) use ($attribute) {
            $this$attribute = $value;
        };

        $setterClosure = Closure::bind($setter, $object, get_class($object));
        $setterClosure($value);
    }
}

Данный трейт принимает объект класса, название свойства, куда нужно установить значение и, собственно, само значение. Далее объявляется простая анонимная функция, которая с помощью указателя $this присваивает полученное значение в свойство класса. Дальше в бой идёт класс Closure с его статическим методом bind(). Метод принимает объект класса, анонимную функцию, описанную выше, и полное имя класса. Таким образом, анонимная функция внедряется в контекст объекта и метод bind() возвращает нам объект класса Closure, который мы можем вызвать как обычную функцию, потому как он определяет магический метод __invoke(). И вуаля!


В итоге мне удалось решить мою проблему, и тогда я вспомнил о шаблоне проектирования Singleton. Получится ли таким же способом внедрить анонимную функцию, которая будет создавать новые объекты класса? Конечно же я пошёл это проверять!


Написав небольшой кусок кода



<?php

final class Singleton
{
    private static $instance;

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

        return self::$instance;
    }

    private function __construct()
    {
    }

    private function __clone()
    {
    }

    private function __wakeup()
    {
    }
}

$s1 = Singleton::getInstance();
var_dump(spl_object_id($s1));

$createNewInstance = function () {
    return new self();
};
$newInstanceClosure = Closure::bind($createNewInstance, $s1, Singleton::class);

$s2 = $newInstanceClosure();
var_dump(spl_object_id($s2));


который работает по такому же принципу, только вместо присвоения значения свойству класса — создаётся новый объект с помощью оператора new. Функция spl_object_id() возвращает уникальный идентификатор объекта. Больше информации об этой функции можно найти в документации. С помощью spl_object_id() и var_dump() вывожу уникальные идентификаторы объектов и вижу то что они отличаются! Мне всё же удалось подтвердить эту теорию и создать новый екземпляр Singleton класса!



В этой статье я хотел поделиться с сообществом PHP моей весьма любопытной находкой.



Спасибо за внимание!



Источник: Хабр / Интересные публикации

Категория: Программирование

Уважаемый посетитель, Вы зашли на сайт как незарегистрированный пользователь.
Мы рекомендуем Вам зарегистрироваться либо войти на сайт под своим именем.

Добавление комментария

Имя:*
E-Mail:
Комментарий:
Полужирный Наклонный текст Подчеркнутый текст Зачеркнутый текст | Выравнивание по левому краю По центру Выравнивание по правому краю | Вставка смайликов Выбор цвета | Скрытый текст Вставка цитаты Преобразовать выбранный текст из транслитерации в кириллицу Вставка спойлера
Введите два слова, показанных на изображении: *