让我们假设我们有注册表模式......
<?php
class Registry
{
private static $objects = array();
private static $instance = null;
public static function getInstance() {
if (self::$instance == null) {
self::$instance = new Registry();
}
return self::$instance;
}
protected function _get($key) {
return ($this->objects[$key]) ? $this->objects[$key] : null;
}
protected function _set($key, $val) {
$this->objects[$key] = $val;
}
public static function get($key) {
return self::getInstance()->_get($key);
}
public static function set($key, $object) {
return self::getInstance()->_set($key, $object);
}
}
?>
使用这种实现真的很容易......
<?
Registry::set('db', $db_client);
Registry::set('redis', $redis_client);
//Using registered objects is really easy
Registry::get('db')->query("...");
Registry::get('redis')->get("...");
?>
但正如您所看到的,即使我们不需要它们,我们也会将实例添加到注册表中(是的,这完全取决于性能)。 所以,问题是......如何修改注册表模式以便能够进行延迟实例化?
这是我正在寻找的......
<?
class Registry
{
private static $objects = array();
private static $instance = null;
public static function getInstance() {
if (self::$instance == null) {
self::$instance = new Registry();
}
return self::$instance;
}
protected function _db() {
if (!$this->objects['db']) {
$this->objects['db'] = new DatabaseAdapter(DB_HOST, DB_NAME, DB_USER, DB_PASSWORD);
}
return $this->objects['db'];
}
protected function _redis() {
if (!$this->objects['redis']) {
$this->objects['redis'] = new Redis(REDIS_HOST, REDIS_DB, REDIS_USER, REDIS_PASSWORD);
}
return $this->objects['redis'];
}
public static function db() {
return self::getInstance()->_db();
}
public static function redis() {
return self::getInstance()->_redis();
}
}
?>
如您所见,DatabaseAdapter()
或Redis()
只会在我们要求时创建。一切似乎都没问题,但是你可以看到它不是一个独立的类,因为_db()
,_redis()
方法包含连接常量等。
怎么避免呢?如何在注册表类中定义注册表方法以将Registy类和其中的对象分开?
我真的很抱歉我的英语,但我希望你能清楚。
谢谢。
PS:上面的所有代码都写了1分钟。以前并没有经过测试。
答案 0 :(得分:4)
如果使用全局常量,则始终依赖于全局范围。这无关紧要。此外,即使您不使用常量,您仍然依赖于Registry中的Database类。如果要解散这些依赖项,可以在要创建的类上使用Factory方法:
public function get($service)
{
if( !this->_data[$service] ) {
// requires PHP 5.2.3
this->_data[$service] = call_user_func($service .'::create');
}
return this->_data[$service];
}
因此,如果您执行get('DB')
,代码将尝试在您要创建的类中调用静态DB::create()
方法。但就像我说的,如果你使用全局常量进行配置,你只需将问题移到另一个类中。
您的db
课程可能如下所示:
class DB
{
protected static $_config;
public static setConfig(array $config)
{
self::_config = $config;
}
public static create()
{
return new self(
self::config['host'],
self::config['db'],
self::config['user'],
self::config['pass']);
}
}
配置可以存储在外部配置文件中,您可以在引导期间加载并设置为DB类,例如。
DB::setConfig(parse_ini_file('/path/to/db-config.ini'));
这样做的缺点是,您必须在整个地方添加create()
方法,并且所有类必须能够存储自己的配置。您可以将这些职责集中到Builder pattern。但是如果你这样做,那么你实现IoC Container只有一半,所以请查看以下资源:
答案 1 :(得分:0)
注意:您正在为$ objects使用“静态”修饰符 - 当您使用实例时,这不是必需的。
如何在注册表类中定义注册表方法以将Registy类和其中的对象分开?
它们总是分开的:注册表类中的每个对象只是对(独立)对象的引用。但是如果这个问题是关于包含适当的类定义(?),你可以使用class_exists()函数在需要时尽快加载类。
BurninLeo