Шаблон реестра и ленивый экземпляр зарегистрированных объектов - PullRequest
4 голосов
/ 07 августа 2010

Давайте представим, что у нас есть шаблон реестра ...

<?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 мин. назад и не был проверен.

Ответы [ 2 ]

4 голосов
/ 07 августа 2010

Если вы используете глобальные константы, вы всегда будете зависеть от глобальной области видимости.Неважно, где это.Кроме того, даже если вы не используете константы, у вас все равно есть зависимость от класса 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 .Но если вы сделаете это, вы на полпути к реализации IoC Container в любом случае, так что проверьте следующие ресурсы:

0 голосов
/ 07 августа 2010

Примечание: вы используете «статический» модификатор для $ objects - поскольку вы работаете с экземпляром, это, вероятно, не обязательно.

Как определить метод реестра в классе реестра для разделения класса Registy и объектов внутри него?

Они всегда отдельные: каждый объект в классе реестра - это просто ссылка на (независимый) объект. Но если этот вопрос касается включения соответствующего определения класса (?), Вы можете использовать функцию class_exists (), чтобы загрузить класс как можно скорее.

BurninLeo

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...