注册模式和注册对象的延迟实例化

Kir*_*lla 5 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);
}

}
?>
Run Code Online (Sandbox Code Playgroud)

使用这个实现非常简单......

<?
Registry::set('db', $db_client);
Registry::set('redis', $redis_client);

//Using registered objects is really easy
Registry::get('db')->query("...");
Registry::get('redis')->get("...");
?>
Run Code Online (Sandbox Code Playgroud)

但正如您所看到的,即使我们不需要它们,我们也会将实例添加到注册表中(是的,这都是关于性能的)。所以,问题是......如何修改注册表模式以便能够进行延迟实例化?

这就是我正在寻找的...

<?
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();
}

}
?>
Run Code Online (Sandbox Code Playgroud)

正如您所看到的,DatabaseAdapter()Redis()只会在我们请求时创建。一切似乎都很好,但正如您所看到的,它不是一个独立的类_db(),因为_redis()方法包含连接常量等。如何避免它?如何在注册表类中定义注册表方法来分离 Registy 类和其中的对象?

我真的很抱歉我的英语不好,但我希望你能明白。

谢谢。

PS:上面的所有代码都是 1 分钟编写的。之前并没有经过测试。

Gor*_*don 4

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

\n\n
public function get($service)\n{\n    if( !this->_data[$service] ) {\n        // requires PHP 5.2.3\n        this->_data[$service] = call_user_func($service .\'::create\');\n    }\n    return this->_data[$service];\n}\n
Run Code Online (Sandbox Code Playgroud)\n\n

因此,如果您这样做get(\'DB\'),代码将尝试调用DB::create()您打算创建的类内的静态方法。但就像我说的,如果您使用全局常量进行配置,您只需将问题转移到另一个类中即可。

\n\n

你的db类可能是这样的:

\n\n
class DB\n{\n    protected static $_config;\n    public static setConfig(array $config)\n    {\n        self::_config = $config;\n    }\n    public static create()\n    {\n        return new self(\n            self::config[\'host\'],\n            self::config[\'db\'],\n            self::config[\'user\'],\n            self::config[\'pass\']);\n    }\n}\n
Run Code Online (Sandbox Code Playgroud)\n\n

配置可以存储在外部配置文件中,您可以在引导期间加载该文件并将其设置为数据库类,例如

\n\n
DB::setConfig(parse_ini_file(\'/path/to/db-config.ini\'));\n
Run Code Online (Sandbox Code Playgroud)\n\n

这样做的缺点是,您必须create()在各处添加方法,并且所有类都必须能够存储自己的配置。您可以将这些职责集中到构建器模式中。但如果你这样做了,你就已经成功实现了IoC 容器的一半,所以请查看以下资源:

\n\n\n