Базовый класс
<?php
class Registry
{
/**
* Хранилище
*/
static private $data = array();
/**
* Сохранение значения
*/
static public function set($name, $value, $space = 'global')
{
self::$data[$space][$name] = $value;
return $value;
}
/**
* Получение значения
*/
static public function get($name, $space = 'global')
{
return isset(self::$data[$space][$name]) ? self::$data[$space][$name] : false;
}
/**
* Очищение всех данных
*/
static public function clear($space = 'global')
{
self::$data[$space] = array();
return true;
}
/**
* Проверка на существование
*
* @since 19.11.2010
* @fail Назвать метод isset() невозможно
*/
static public function is_set($name, $space = 'global')
{
return isset(self::$data[$space][$name]);
}
/**
* Дамп данных
*
* @since 19.11.2010
*/
static public function dump($space = 'global')
{
return self::$data[$space];
}
}
?>
Производные классы, для хранения данных в других областях видимости строятся по подобию
<?php
class MF_Registry extends Registry
{
static private $space = 'MF';
static public function set($var_name, $var_set){return parent::set($var_name, $var_set, self::$space);}
static public function get($var_name){return parent::get($var_name, self::$space);}
}
?>
Возможно ли усовершенствовать такой механизм?
Я хоть не Дональд Кнут, и моё мнение не абсолютная истина, но, раз уж прозвучал вопрос...
Итак, первое, самое очевидное - в переменной $space нет никакого смысла. Различные имена реестров уже на 100% достаточно разделяют области видимости.
Дальше. Всё, что не может быть подсказано IDE,
a) Может стать причиной опечатки
b) Не может быть проверено до выполнения, что увеличивает количество "подводных камней" - ошибок, которые проявляются не сразу при запуске, а позже, в процессе использования.
Поэтому методы set и get использовать в текущем виде нельзя (имена полей передаются в виде строк).
Честно говоря, к реестру, на мой взгляд, не применима инкапсуляция, поскольку реестр не является объектом, обрабатывающим свои свойства. В реестре вполне можно объявить public свойства и использовать их. Всё равно любой класс может вызвать и get и set и никаких проверок соответствию типа ни в get ни в set быть не может, поскольку тип всех переменных сразу не задашь. А вот при получении данных из реестра, объект очень легко может проверить соответствие типа, что он и должен сделать.
Однако, если уж хочется именно соблюсти, то можно создавать методы с явными именами, вроде "setNameOfProperty" и "getNameOfProperty".
Это кажется сложным и не универсальным, но, учтите, что реестр будет использовать только само приложение! Никакой из объектов не должен обращаться к реестру напрямую.
Из реестра будут только передаваться значения при создании объектов.
Например, приложение может создать
$controller=new MainController(MF_Registry::$params);
это правильный вариант.
А когда объект MainController сам обращается к реестру по имени, это неправильный вариант. Никто из объектов не должен знать о существовании реестра. Иначе все они станут зависимы от реестра. То есть, при изменении реестра, нерабочими станут ВСЕ объекты, которые использовали его. Это недопустимо.
Так вот, я отвлёкся.
Если не возводить здесь не нужную (на мой взгляд) инкапсуляцию, можно просто объявить нужные имена полей и всё, реестр готов.
С инкапсуляцией эти поля будут protected и всем им нужно будет создать getter и setter. Но это уже детали.
А в каждом расширяющем классе просто добавлять свои поля.
Кстати, чтобы расширяющий класс мог использовать свойство родителя, оно должно быть protected, не private.
По поводу реестра в целом - не храните в реестре функции, храните только переменные. Ваши объекты не будут знать имя реестра, значит им нужно будет передать ссылку на функцию. Это возможно с обычным объектом (передать ссылку на экземпляр), но не со статическим. Поэтому хранить функции нужно именно в обычных (динамических) классах.
Ну и зачем собственно так задрачиваться?
у меня в реестре только 2 метода: Set и Get. И то Get возвращает не одно свойство, а массив со свойствами. Принимаю дескриптор реестра в конструкторе, назначаю ему переменную и потом работаю с этим массивом.
Области видимости... Какие еще области видимости, они нахер не нужны.
3, я собственно, использую статические методы именно для того что бы не пришлось каждый раз передавать объект реестра.
01 Дек 2010, 15:192, у меня [пока что] монолитная структура.
Имена областей хранения (то бишь $spac'ы) нужны для отделения областей.
Цитата:
"Кстати, чтобы расширяющий класс мог использовать свойство родителя, оно должно быть protected, не private."
В производных классах не нужно использование свойства $data (если ты про него).
Цитата:
"Итак, первое, самое очевидное - в переменной $space нет никакого смысла. Различные имена реестров уже на 100% достаточно разделяют области видимости."
Производные класса обращаются к универсальным сеттерам/геттерам, передавая им и область видимости, из которой/в которую помещаются данные.
Morgan,
1) разные имена реестра более чем достаточно разделяют области видимости. $space не нужна.
2)
"В производных классах не нужно использование свойства $data"
Да, а в методах get/set оно не используется разве? Private - значит доступно только родительскому классу.
3)
"Производные класса обращаются к универсальным сеттерам/геттерам"
Вместо цитирования ты мог написать, почему тебе хочется делать именно так, даже после того, как я рассказал, почему это не самый лучший вариант.
В данный момент твой реестр абсолютно ничем не отличается от массива $GLOBALS.
Обычный реестр в виде статического класса мог, хотя бы, помочь не делать опечатки в именах свойств, а этот и того не делает.
Напиши, для чего нужен реестр, как он будет использоваться - может подскажем чего. Хотя ты не особо слушаешь советы 
6, производные классы обращаются к методам базового класса, больше они ничего не делают.
Производные классы, напрямую, никакие дейсвия с массивом не производят.
Цитата:
"Обычный реестр в виде статического класса мог, хотя бы, помочь не делать опечатки в именах свойств, а этот и того не делает."
?
Цитата:
" ничем не отличается от массива $GLOBALS."
Отличается.
Есть базовый класс, Registry.
От него производный - MF_Registry.
В Registry я храню такие данные как, объект для работы с бд/шаблонизатором.
В MF_Registry я храню системные данные.
Данные о модулях, данные роутинга.
Т.е. в MF_Registry хранятся данные, которые используются только во внутренностях системы.
Morgan, абсолютно тоже самое Вы можете хранить в массиве $GLOBALS, разницы нет никакой.
"Т.е. в MF_Registry хранятся данные, которые используются только во внутренностях системы."
Это правильный подход. Главное не забывать, что внутри всех классов не должно быть обращения к этому реестру по имени.
Реестр начинает отличатся от $GLOBALS тогда, когда у статического класса появляются именованные поля (свойства), а не какие-то призрачные get/set. Если уж IDE не пользуетесь и автокомплит не аргумент - подумайте о возможности отправлять значение по ссылке.
$GLOBALS это системная переменная, трогать ее - плохо!!! Пусть себе живет. Registry с "именнованными полями" в похапе получается в одном варианте, когда он не статичен, а значит мы теряем в глобальной области видимости. А значит нужно строить огромную цепочку передач регистра в объекты и 100% где то нужно его похерить и вырвимозгом заниматься. А еще.. а еще мы юзаем няшку в виде уже не призрачных, а магических __get и __set, ведь вы же хотите иметь не только жестко заданные параметры? Потому что ЖЗП - плохо! И снова имеем то, что имеем ide не будут комплитить обработку __get/__set.
З.Ы. Усовершенствовать именно это механизм можно аж так:
{return parent::set($var_name, $var_set, __CLASS__);}
Только зачем нам два регистра со всякой туфтой, которая прекрасно ложиться в один?
Почему бы не сделать один суперкласс ( скажем Component) который будет обрабатывать что-то вроде $this->db у всех потомков и выдавать им коннект к бд? или $this->template будет выдавать всем потомкам один и тот же шаблонизатор. А вот эти куча регистров-запутайсамсебя вам не нужны 