Реализация реестра объектов в CMS, ваши мнения о плюсах и минусах данной реализации

Nelius

кипарис во дворе
Реализация реестра объектов в CMS, ваши мнения о плюсах и минусах данной реализации

Вот пытаюсь привести свою CMS хоть к какому-то божескому виду...
Много всего прочитал за эти не дни, в том числе и то что советовали люди в топиках форума phpclub.ru, вот родил кое-какую реализацию реестра основываясь на статье "Управление зависимостями в PHP-коде" с Agiledev.ru в которой были разобраны разные подходы к решению задачи обеспечения доступа к объектам.
Хотелось бы мнений более опытных в данном вопросе людей о минусах данной реализации и общее мнение об удобстве использования данной реализации.

Код:
PHP:
class CORE {
	private static $rst = array(array());

	public static function register($name,$obj) {
		if (!self::is_registered($name)) { self::$rst[0][$name] = $obj; }
		else { throw new Exception ('Error #001: Object with name '.$name.' was already registered'); }
	}
	public static function get($name) {
		if (self::$rst[0][$name] !== null) { return self::$rst[0][$name]; }
		else { throw new Exception ('Error #002: Object not registered'); }
	}
	public static function is_registered($name) { return @(self::$rst[0][$name] !== null); }
	public static function save($copy=1) {
		if($copy) { array_unshift(self::$rst,self::$rst[0]); }
		else { array_unshift(self::$rst,array()); }
	}
	public static function restore() { array_shift(self::$rst); }

	public static function Produce($cname,$fname='',array $construct_arg=array(),$fdir='_includes/',$req=1) { // Factory
		$cname = strtolower($cname);
		if ($req) {
			if ($fname != '') { require_once($fdir.$fname); }
			return new $cname($construct_arg);
		}
		else {
			if ($fname != '') { 
				if (include_once($fdir.$fname)) { return new $cname($construct_arg); }
				else { throw new Exception ('Error #003: Driver not found'); }
			}
			else { return new $cname($construct_arg); }
		}
	}
}

class Config { //Упрощенный класс для примера
	public $config = array();

	public function set($key,$val)  { $this->config[$key] = $val; }
	public function get($key) {return $this->config[$key[0]]; }
}

class DB { //Упрощенный класс для примера
...
}

class Foo { //Упрощенный класс для примера использования реестра, вариант 1
	protected
		$db,
		$cfg;

	function __construct($arg) {
		$this->db = CORE::get('DB');
		$this->cfg = CORE::get('CONFIG');
	}

	public function Bar()  { return $this->db->query('SELECT * FROM something'); }
}

class NeFoo { //Упрощенный класс для примера использования реестра, вариант 2
	public function NeBar()  {
		$db = CORE::get('DB');
		$cfg = CORE::get('CONFIG');
		return $db->query('SELECT * FROM something');
	}
}

$cfg = CORE::Produce('Config');
CORE::register('CONFIG', $cfg);

$db = CORE::produce('DB',$cfg->get('db1,engine').'.lib.php');
CORE::register('DB', $db);

$foo = CORE::Produce('Foo');
CORE::register('FOO', $foo);
print $foo->bar();

$nefoo = CORE::Produce('NeFoo');
CORE::register('NEFOO', $nefoo);
print $nefoo->nebar();
Пинания за кривые решения и недопонимание основ приветствуются, тыканья носом в мануалы приветствуются вдвойне! :)

P.S. Я разрабатываю OpenSource CMS и поэтому мне очень важны отзывы о том хорошо ли или неочень использовать тот или иной подход и главное удобно ли было бы Вам как разаботчикам разрабатывать дополнительные модули на основе данного решения...
Я бы мог забить на все и просто писать как хочу, мне то мой код любой понятен, но имея бооольшой опыт в изучении и правке чужого кода... мне хотелось бы уделить больше времени вопросам не только быстрой и красивой, но и удобной для разработчиков реаллизации основных функций ядра CMS.
Заранее всех благодарю за помощь.
 

HraKK

Мудак
Команда форума
чем тебе банальный Registry не понравился в 3 строчки? Зачем эти танцы вокруг костра?
Я вообще отказался от регистра в пользу синглетона, да и его надо применять с головой что бы потом не оказалось пол классов-синглетоны.
 

Nelius

кипарис во дворе
Тут и есть банальный Registry в 3 строчки, просто хранилище реализованно в виде двумерного массива для того чтобы можно было сохранять состояние Registry и восстанавливать его.(реализацию с 2-мерным массивом я увидел в статье с AgileDev мне она очень понравилась своей изящностью, идеей использования array_shift и array_unshift вот я и решил использовать их опыт) Если выкинуть двумерный массив и методы save и restore то получается банальный Registry из 3-х строчек + Фабрика.

HraKK
Я вообще отказался от регистра в пользу синглетона
Я тоже рассматривал синглетон, пробовал писать с его использованием, но он не во всем меня устраивает так что я решил отказаться от такой реаллизации.
В этой статье хорошо написанно про недостатки синглеона и недостатки Registry я больше склоняюсь к использованию Registry.

К томуже данная реализация(реестр) позволяет, например:
PHP:
$MySQL = CORE::produce('MySQL',$cfg->get('db1,engine').'.lib.php'); 
$core->register('MySQL', $MySQL);
$MySQLi = CORE::produce('MySQLi',$cfg->get('db2,engine').'.lib.php'); 
$core->register('MySQLi',$MySQLi);
$PgSQL = CORE::produce('PgSQL',$cfg->get('db3,engine').'.lib.php'); 
$core->register('PgSQL', $PgSQL);
И все это буит прекрасно рабоать) Только не спрашивайте зачем это нужно))))
 

whirlwind

TDD infected, paranoid
Nelius включи error_reporting(E_ALL)
Вообще рекомендую прекратить использовать trigger_error-ы и амперсанды. Добавь в get проверку is_registered и выкидывай исключение, если не зареган. Иначе может быть ситуация когда будешь ооочень долго искать ошибки.

ЗЫ. Я бы все таки не стал совать Produce в реестр.
 

Nelius

кипарис во дворе
Автор оригинала: whirlwind
Nelius включи error_reporting(E_ALL)
Вообще рекомендую прекратить использовать trigger_error-ы и амперсанды. Добавь в get проверку is_registered и выкидывай исключение, если не зареган. Иначе может быть ситуация когда будешь ооочень долго искать ошибки.

ЗЫ. Я бы все таки не стал совать Produce в реестр.
Спасибо что откликнулись!
error_reporting(E_ALL) - включен, сообщений нет
По поводу trigger_error понятно, поизучаю этот вопрос, а вот по поводу амперсандов не совсем ясно почему не стоит их использовать?
Про is_registered спасибо, это действительно необходимо.
И еще прошу пояснить почему стоит отделить Фабрику.
 

whirlwind

TDD infected, paranoid
>error_reporting(E_ALL) - включен, сообщений нет
И на это
PHP:
public function &instance() {
...
CORE::instance();
?

> по поводу амперсандов не совсем ясно почему не стоит их использовать?

Потому что они заставляют лишний раз задуматься, хотя на самом деле абсолютно ничего не значат.

Вот это плохо
PHP:
   static $registry=false; 
        if (!$registry) { $registry = new CORE(); } 
        return $registry;
потому что в случае необходимости ты не сможешь сделать setInstance(CORE $instance)

>И еще прошу пояснить почему стоит отделить Фабрику.

Потому что реестр - это реестр. Он хранит объекты и абсолютно не обязан знать, что файлы лежат в '_includes/' и конструкторы всех классов принимают 1 аргумент. Захочешь поменять загрузчик, придется менять код реестра.

Вот здесь непонятно
PHP:
public function save() { 
        array_unshift($this->rst,array()); 
        if (!count($this->rst)) { trigger_error('Error #001: Registry is empty',E_USER_ERROR); } 
    }
Если ты сделал unshift то как у тебя может быть !count ?
И вообще имхо такой вариант стека не очень полезен.
Я бы аншифтил дубликат того массива, что сейчас на вершине. В этом случае достаточно перекрыть только те объекты, которые требуют изменений/подмены/замены етс, вместо того, что бы заново регистрировать все объекты.
 

Nelius

кипарис во дворе
Есть только нотисы по поводу "Undefined variable" о них мне известно ну и варнинг из-за этих нотисов про сессию)))
на & поидее должен был ругнуться, я прочел про это в мануале, но не ругнулся... пхп 5.2.5
ну да ладно уже все равно исправил.

Про амперсанды понял, уже не использую.

и конструкторы всех классов принимают 1 аргумент
Это не один аргумен а массив аргументов, наверное стоит явно это указать.

Потому что реестр - это реестр.
Ну у меня была идея такова... реестр входит в ядро системы, так же как и фабрика... соответственно ядро "знает" все обо всех "инструментах" которыми располагает в данный момент, и может предоставить эти инструменты, а также при необходимости создавать их. Незнаю может это и неверный подход...

-~{}~ 14.11.07 22:54:

Обновил код...

Добавил проверки в get и register. В register для того чтобы не было проблем, если в каком-то модуле в реестр добавят объект, с именем, которое совпадет с именем ранее зарегистрированного объекта.

Теперь по умолчанию происходит копирование а не замена в методе save(). (отдельное спасибо Вам за идею)

Осталось несколько вещей которые мне не до конца понятны:
whirlwind
рекомендую прекратить использовать trigger_error
Вы предлагаете использовать throw new Exception? Просто trigger_error используется в официальных примерах на php.net. Я пытаюсь понять использование данной функции не рекомендуется из логических умозаключений(может она тут не к месту?) или же есть в ней какой-то скрытый негативный момент?

Еще вопрос, обоснованно ли явное указание директории '_includes' в фабрике или стоит убрать?

whirlwind большое Вам спасибо что помогаете!
 

Fred

Новичок
Nelius

Я от плавно перешел от объектов-синглтонов к регистру-синглтону

PHP:
$registry = Registry::getInstance();
$obj = $registry->get("obj");
а затем к полностью статическому реестру
PHP:
$obj = Registry::get("obj");
Код реестра действительно получается в 3 строчки :)

Автор оригинала: HraKK
Я вообще отказался от регистра в пользу синглетона, да и его надо применять с головой что бы потом не оказалось пол классов-синглетоны.
Их неудобно тестировать ;)
 

whirlwind

TDD infected, paranoid
использовать throw new Exception? Просто trigger_error используется в официальных примерах на php.net. Я пытаюсь понять использование данной функции не рекомендуется из логических умозаключений(может она тут не к месту?) или же есть в ней какой-то скрытый негативный момент?
Скорее нет позитивного. Только не стоит увлекаться исключениями. Это должны быть именно "исключительные" ситуации, а не все подряд ошибки. Как только получишь первое неотловленное исключение, так сразу и поймешь в чем преимущество перед trigger_error.

явное указание директории '_includes' в фабрике или стоит убрать?
Заменить на set_include_dir() на этапе инициализации или на атрибут класса с акцесором/мутатором, что бы можно было изменять это значение.
 

Nelius

кипарис во дворе
Автор оригинала: Fred
Я от плавно перешел от объектов-синглтонов к регистру-синглтону
а затем к полностью статическому реестру
Я как раз думал о том чтобы поробовать реаллизовать реестр как синглтон, а потом прочел ваше сообщение и реализовал как статический)
Большое Вам человеческое спасибо! Действительно так намного проще и удобней.

-~{}~ 15.11.07 14:42:

whirlwind
Большое спасибо, Вы мне действительно очень сильно помогли советами.
Я понимаю что моя просьба о помощи(топик) возможно не совсем корректна и к тому же я привел пример с достаточно большим объемом кода, но я задал его только потому что проект OpenSource и мне хочется сделать его качественно, чтобы он принес пользу не только мне, но и другим людям.
Так что отдельная Вам благодарность за то что нашли время посмотреть и вникнуть в код.
 

atv

Новичок
Я вот добавил в Registry ещё и namespaces: Registry. К тому же, его легко заюзать для других задач: Session. Пример использования: Registry.
 

Nelius

кипарис во дворе
atv
Спасибо что поделились опытом! Вникаю вот как у вас реаллизован реестр....
В целом, как я понял, ваша идея с нэймспэйсез это более совершенная реаллизация save и restore в моем примере :)
Но я просмотрел бегло так что могу ошибаться... буду дальше вникать...
 

atv

Новичок
В целом, как я понял, ваша идея с нэймспэйсез это более совершенная реаллизация save и restore в моем примере
не совсем, или совсем не :)

у тебя есть метод register($name,$obj), так вот объектов может быть очень много, и для каждого нужно придумать $name, а namespace позволяет разграничить, так сказать, области видимости, например по именам модулей...
 

Nelius

кипарис во дворе
Понял, спасибо) Идея хорошая у вас, нужно только понять есть ли в нэймспэйсах необходимость для моего проекта. Щас вот сижу пытаюсь ситуации представить :)
 
Сверху