php - 注册表模式和注册对象的惰性实例化

标签 php oop registry design-patterns

假设我们有注册表模式...

<?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 分钟写的。之前没有经过测试。

最佳答案

如果您使用全局常量,您将始终依赖于全局范围。它在哪里并不重要。此外,即使您不使用常量,您仍然依赖于注册表中的数据库类。如果你想解除这些依赖关系,你可以在要创建的类上使用工厂方法:

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::setConfig(parse_ini_file('/path/to/db-config.ini'));

这样做的缺点是,您必须到处添加 create() 方法,并且所有类都必须能够存储自己的配置。您可以将这些职责集中到一个 Builder pattern 中.但是如果你这样做,你就已经完成了 IoC Container 的一半。无论如何,请查看以下资源:

关于php - 注册表模式和注册对象的惰性实例化,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/3429758/

相关文章:

windows - 如何增加 Windows 10 的最大 GDI 对象数量?

php - 具有多个上传文件的动态元素

php - 在 codeigniter 中的模型中运行多个查询

python - 检查具有不同属性的对象是否相等

c++ - 检测键是否是加载/安装的注册表配置单元的根

powershell - 搜索注册表并创建新项目

PHP + MySQL : When I select from two tables, 如何定义我要从哪个表中取 "id"

php - MySQL重复条目错误,即使它不是重复条目

python - 继承 : transform a base class instance to a child class instance

java - 用对象重写Java中的equals方法