Построение черты Singleton с PHP 5.4

Недавно у нас было обсуждение, если можно было создать trait Singleton PHP Traits, и мы играли с ней в возможной реализации, но столкнулись с проблемами со строительством.

Это академическое упражнение. Я знаю, что у Singletons have very little - if not to say no - use in PHP и что one should 'just create one' а просто для изучения возможностей черт:

 <?php trait Singleton { protected static $instance; final public static function getInstance() { return isset(static::$instance) ? static::$instance : static::$instance = new static; } final private function __construct() { static::init(); } protected function init() {} final private function __wakeup() {} final private function __clone() {} } class A { use Singleton; public function __construct() { echo "Doesn't work out!"; } } $a = new A(); // Works fine 

воспроизводить: http://codepad.viper-7.com/NmP0nZ

Вопрос в том, можно ли создать черту Singleton в PHP?

Solutions Collecting From Web of "Построение черты Singleton с PHP 5.4"

Быстрое решение, которое мы нашли (спасибо чату!):

Если признак и класс определяют один и тот же метод, один из классов, если используется

Таким образом, свойство Singleton работает только в том случае, если класс, который его использует, не определяет __construct()

Черта:

 <?php trait Singleton { protected static $instance; final public static function getInstance() { return isset(static::$instance) ? static::$instance : static::$instance = new static; } final private function __construct() { $this->init(); } protected function init() {} final private function __wakeup() {} final private function __clone() {} } 

Пример для класса потребления:

 <?php class A { use Singleton; protected function init() { $this->foo = 1; echo "Hi!\n"; } } var_dump(A::getInstance()); new A(); 

Теперь var_dump производит ожидаемый результат:

 Hi! object(A)#1 (1) { ["foo"]=> int(1) } 

и новый не удается:

 Fatal error: Call to private A::__construct() from invalid context in ... 

Demo

Я создал его некоторое время назад, когда мне было скучно, пытаясь узнать черты. Он использует отражение и постоянную __CLASS__

Черта:

 trait Singleton { private static $instance; public static function getInstance() { if (!isset(self::$instance)) { $reflection = new \ReflectionClass(__CLASS__); self::$instance = $reflection->newInstanceArgs(func_get_args()); } return self::$instance; } final private function __clone(){} final private function __wakeup(){} } 

Таким образом, вы можете продолжать использовать метод __construct () и не должны использовать произвольную функцию в качестве конструктора.

Дело в том, что тип возврата getInstance будет неоднозначным, поскольку он зависит от потребителя. Это дает слабую типизированную подпись метода. Например, это делает невозможным предоставление @ comeurn в соответствии с типом потребителя в блоке doc метода getInstance.

Это все, что вам нужно. Если вы хотите, чтобы вы могли использовать частный статический член, но нет реальной потребности … Протестировано, работает, несмотря на то, что вы можете подумать, что статический будет глобальным или чем-то 🙂

 trait Singleton { /** * Singleton pattern implementation * @return mixed */ public static function Instance() { static $instance = null; if (is_null($instance)) { $instance = new self(); } return $instance; } } 

Применение:

 class MyClass { use Singleton; }