Паттерн Singleton (Одиночка) уже многократно обсуждался, тем не менее я не нашел решения позволяющего реализовать наследование от Singleton-а не нарушающего основной идеи Singleton-а — скрытие конструктора класса.
Ниже приведен пример моей реализации такого механизма не нарушающего сущность паттерна с использованием трэйта.
singleton.php
<?php // Трэйт с реализацией фабричного метода trait Trait_Singleton { // Фабричный метод public static function getInstance() { static $_instance; if ($_instance === null) { $_instance = new self(); } return $_instance; } } // Реализация паттерна Singleton class Pattern_Singleton { use Trait_Singleton; // Запрещаем внешний вызов __clone protected function __clone() {} // Запрещаем внешний вызов __wakeup() protected function __wakeup() {} // Запрещаем внешний вызов __construct protected function __construct() {} } ?>
Пример использования
singleton_sample.php
<?php include_once 'singleton.php'; //----------------------------------------------- // Реализация базового класса Our, // родителя для My и Your //----------------------------------------------- class Our extends Pattern_Singleton { use Trait_Singleton; public $class_name = 'Our'; public $instance_id; // Реализация конструктора для класса Our protected function __construct() { parent::__construct(); $this->instance_id = rand(); } // Метод для отображения содержимого класса Our и его потомков public function showMe() { echo '<h2>'.$this->class_name.'</h2><pre>'; print_r($this); echo '</pre>'; } } //----------------------------------------------- // Реализация класса Your // // Этот класс просто расширяет функциональность // родителя, добавлением свойства $msg и его // инициализацией в конструкторе //----------------------------------------------- class Your extends Our { use Trait_Singleton; public $class_name = 'Your'; public $mgs = ''; // Реализация конструктора для класса Your protected function __construct() { parent::__construct(); $this->mgs = 'Your random id is '.$this->instance_id; } } //----------------------------------------------- // Реализация класса My // // Этот класс расширяет функциональность родителя, // добавлением свойств $msg и $my_val. // При этом $my_val должен инициализироваться из // параметра конструктора. В связи с этим // необходимо переопределить фабричный метод // непосредственно в данном классе. //----------------------------------------------- class My extends Our { // use Trait_Singleton; // Не обязательно указывать, так как // единственный метод трэйта переопределен // в классе public $class_name = 'My'; public $mgs = ''; public $my_val; // Перекрываем фабричный метод трэйта, так как // надо передать параметр public static function getInstance($val=null) { static $_instance; if ($_instance === null) { $_instance = new self($val); } return $_instance; } // Реализация конструктора для класса My protected function __construct($val=null) { parent::__construct(); $this->mgs = 'My random id is '.$this->instance_id; $this->my_val = $val; } } //=============================================== // Пример использования //=============================================== // Создаем экземпляр Your $O1 = Your::getInstance('1st Your'); $O1->showMe(); $O2 = Your::getInstance('2nd Your'); $O2->showMe(); // Создаем экземпляр My $O3 = My::getInstance('My Value !!!'); $O3->showMe(); $O4 = My::getInstance(); $O4->showMe(); // Создаем экземпляр Our $O5 = Our::getInstance(); $O5->showMe(); $O6 = Our::getInstance(); $O6->showMe(); ?>
Таким образом, мы получаем некоторую иерархию классов, которые наследуются от Singleton и позволяют нам получить лишь по одному экземпляру каждого класса иерархии.