Registry
![]() |
Это теоритическая часть, практическую можно найти на странице CORE |
|---|
Ну я думаю стоит начать из далека... когда еще деревья были большими а колбаса вкусной...
Нет это слишком рано ;) Начнем с того что паттерны в программировании были придуманы никак не для PHP, а для Smalltalk. Ну а к PHPони были притянуты "за уши", с появлением 5-ой версии.
Идея паттерна Registry состоит в том что проект (читай : сайт) содержит много разнообразных классов, например класс для работы с БД и шаблонизатор. А теперь появился класс User который должен работать с БД и передавать данные шаблонизатору. Значит он должен знать о функциях SELECT и ASSIGN двух других классов. Классы можно было бы наследовать и получить этот доступ но наследовать в PHP можно только один класс, да и если проект большой то стоит ли наследовать 150 разных классов?! Значит надо передавать экземпляры классов в функции которые их используют, или еще лучше в конструктор а там присвоить их свойствам. А зачем передавать(?!) можно сразу создать новый экземпляр прямо в конструкторе User'a, допустим, а если при создании конструкторам нужно передавать параметры? Или можно использовать паттерн Singleton для того чтобы не пересоздавать объект каждый раз но это не всегда удобно. Ну, а что если, например вы решите сменить шаблонизатор с XTemplate на Smarty и придется искать и реплейсить все названия класса.
И придумали умные программисты создавать один класс который бы знал о всех остальных, и раздавал кому нужно ссылки на них! При всем этом желательно чтоб еще никто не создал случайно второй экземпляр этого чудо класса поэтому в нем используют паттерн Singleton Еще неплохо было бы там использовать фабричные методы но мы это опустим... покрайней мере пока
Итак создадим класс A и скажем что напрямую его создать нельзя будет, но можно создать через функцию instance(), а также создадим статичный метод для регистрации некого объекта B о котором известно только что он создается напрямую через конструктор.
class A{
public $registry;
private static $instance;
private function __construct(){
echo "A::__construct()\n";
}
static function & instance(){
if (!isset(self::$instance)){
self::$instance = new self;
}
return self::$instance;
}
public static function register(&$obj){
$instance =& A::instance();
$instance->registry = $obj;
}
public function __destruct(){
echo "A::__destruct()\n";
}
}
class B {
public function __construct(){
echo "B::__construct()\n";
}
public function __destruct(){
echo "B::__destruct()\n";
}
}
A::instance();
A::register(new B);
//RESULT :
//A::__construct()
//B::__construct()
//A::__destruct()
//B::__destruct()
Создали, зарегистрировали, прикольно. Теперь обратите внимание на порядок следования деструкторов. Логично было ло бы, чтоб деструктор класса A вызывался ПОСЛЕ деструктора B для этого изменим несколько строк
public function __destruct(){
$instance =& A::instance();
$instance->registry = null;
echo "A::__destruct()\n";
}
//RESULT :
//A::__construct()
//B::__construct()
//B::__destruct()
//A::__destruct()
Теперь вроде бы все правильно деструкторы вызываются в правильной последовательности, но регистрация одного класса ничего не даст надо регистрировать много классов и следить чтобы их деструкторы вызывались в правильной последовательности
class A{
public $registry;
private static $instance;
private function __construct(){
echo "A::__construct()\n";
}
static function & instance(){
if (!isset(self::$instance)){
self::$instance = new self;
}
return self::$instance;
}
public static function register(&$obj,$name){
$instance =& A::instance();
$instance->registry[$name] =& $obj;
}
public static function & extract($name){
$instance =& A::instance();
return $instance->registry[$name];
}
public static function unregister($name) {
unset($instance->registry[$name]);
}
public function __destruct(){
echo "Вызван деструктор A\n";
$instance =& A::instance();
foreach ($instance->registry as $name => &$obj){
echo "Вызван деструктор $name\n";
$obj = null;
}
echo "Объект разрушен A\n";
}
}
class B{
public function __construct(){
echo "B::__construct()\n";
}
public function __destruct(){
echo "Объект разрушен B\n";
}
}
class C{
public function __construct(){
echo "C::__construct()\n";
}
public function __destruct(){
unset($this->B);
echo "Объект разрушен C\n";
}
}
A::instance();
A::register(new B,'B');
A::register(new C,'C');
//RESULT
//A::__construct()
//B::__construct()
//C::__construct()
//Вызван деструктор A
//Вызван деструктор B
//Объект разрушен B
//Вызван деструктор C
//Объект разрушен C
//Объект разрушен A
Однако на этом проблемы не заканчиваются. Случилось собственно то ради чего все это затевалось В объекте класса C понадобилась информация об объекте класса B
class C{
public $B;
public function __construct(){
echo "C::__construct()\n";
$this->B =& A::extract('B');
}
public function setB(&$B){
$this->B =& $B;
}
public function __destruct(){
echo "Объект разрушен C\n";
}
}
A::instance();
A::register(new B,'B');
A::register(new C,'C');
// или переприсваисаем значение через seter
A::extract('C')->setB(A::extract('B'));
//RESULT :
//A::__construct()
//B::__construct()
//C::__construct()
//Вызван деструктор A
//Вызван деструктор B
//Объект разрушен B
//Вызван деструктор C
//Объект разрушен C
//Объект разрушен A
Примерно так выглядело ядро, этого сайта, пока я не перешел на WordPress, только немного сложнее - с добавлением фабричных методов.

Свежие комментарии