Нашел способ обхода стандартной реализации паттена Singletion с помощью php Reflection Api.
Стандартная реализация выглядит примерно так:
class Singleton {
static private $instance = null;
private function __construct() { /* ... @return Singleton */ } // Защищаем от создания через new Singleton
private function __clone() { /* ... @return Singleton */ } // Защищаем от создания через клонирование
private function __wakeup() { /* ... @return Singleton */ } // Защищаем от создания через unserialize
static public function getInstance() {
return
self::$instance===null
? self::$instance = new static()//new self()
: self::$instance;
}
}
Используя ReflectionClass мы можем создать экземпляр объекта нужного нам класса, в том числе в обход метода __construct()
$ref = new ReflectionClass('className');
$third = $ref->newInstanceWithoutConstructor();
Вот полный пример, в котором первые 2 объекта Singleton создаются стандартным способом, а третий через Reflection
class Singleton {
static private $instance = null;
private function __construct() { /* ... @return Singleton */ } // Защищаем от создания через new Singleton
private function __clone() { /* ... @return Singleton */ } // Защищаем от создания через клонирование
private function __wakeup() { /* ... @return Singleton */ } // Защищаем от создания через unserialize
private $value = "Изначальное значение свойства";
static public function getInstance() {
return
self::$instance===null
? self::$instance = new static()//new self()
: self::$instance;
}
/**
* обновить значение приватного свойства
* @param [type] $v [description]
*/
public function setValue($v) {
$this->value = $v;
}
/**
* получить значение приватного свойства
* @return [type] [description]
*/
public function getValue() {
return $this->value;
}
}
$first = Singleton::getInstance();
$first->setValue('Обновленное значение свойства');
var_dump('$first->getValue: ' . $first->getValue());
$second = Singleton::getInstance();
var_dump('$sceond->getValue: ' . $second->getValue());
var_dump('$first===$second: '.(($first===$second)? 'true':'false'));
$ref = new ReflectionClass('Singleton');
$third = $ref->newInstanceWithoutConstructor();
var_dump('$third->getValue: ' . $third->getValue());
var_dump('$third instanceof Singleton: ' . (($third instanceof Singleton)? 'true':'false'));
var_dump('$third===$second: '.(($third===$second)? 'true':'false'));
В итоге мы видим, что третий объект является инстансом класса Singleton, но обладает другими свойствами.
$ php reflection.php
"$first->getValue: Обновленное значение свойства"
"$sceond->getValue: Обновленное значение свойства"
"$first===$second: true"
"$third->getValue: Изначальное значение свойства"
"$third instanceof Singleton: true"
"$third===$second: false"
Внимание вопрос: есть ли возможность создать полностью защищенный синглтон, что бы избежать в том числе и такую возможность создания инстанса в обход стандартной реализации.
Паттерны проектирования существуют для облегчения разработки и сопровождения кода, а не для того, чтобы "запретить и не пущать".
Если в какой-то момент разработчик пал столь низко, что решил использовать в рабочем коде рефлексию, то это в большинстве случаев (не рассматриваем особые случаи, типа тестов, фреймворков и т.д.) говорит о больших проблемах. А уж если с помощью рефлексии стали "ломать" синглтон, то это повод очень всерьез задуматься, нужен ли он там.
Что касается мифического "внешнего вмешательства". Использовать рефлексию может только а) человек, который знает, что это такое, б) имеющий доступ к вашему коду и с) если ему действительно понадобилось использовать рефлексию. Как вы заметили, условие б) в 99.99% случаев позволяет обойтись вообще без рефлексии. А остальные 0.01% случаев выпадают на условие с), например для написания экзотических тестов
PS Отвечая на вопрос. Reflection для того и создавался, чтобы можно было ковыряться в кишках объектов и собирать любых франкенштейнов. Не напишите вы синглтон, который будет защищен от рефлексии.
Современные инструменты для криптотрейдинга: как технологии помогают принимать решения
Апостиль в Лос-Анджелесе без лишних нервов и бумажной волокиты
Основные этапы разработки сайта для стоматологической клиники
Продвижение своими сайтами как стратегия роста и независимости