Реестр конфигов - как реализовать

Я после некоторого ввода/руководства. У меня есть приложение, которое использует центральный реестр конфигурации, как показано ниже..

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

Я вижу несколько возникающих проблем, в том числе:

  1. Конфликты имен между файлами и переменными, установленными в скрипте
  2. Невозможность извлечения вложенных переменных массива приводит к следующему коду:

    $databases = config::get('база данных'); $actual_record = $базы данных['по умолчанию'];

У меня возник соблазн добавить второй параметр get для вложенного значения, однако что произойдет в будущем, если мне нужно будет получить значение 3-го или 4-го уровня.

class config
{
   private static $registry;

   /**
   *
   */
   private function __construct() {}

   /**
   *
   */
   public static function get($key)
   {
      if (isset(self::$registry[$key])) return self::$registry[$key];
      else return FALSE;
   }

   /**
   *
   */
   public static function set($key, $value, $overwrite = FALSE)
   {
      // Does the variable already exist?
      if (isset(self::$registry[$key]) && $overwrite === FALSE) 
         throw new Exception();

      self::$registry[$key] = $value;
   }
}

Заранее спасибо за помощь..


person Lee    schedule 05.02.2012    source источник
comment
Вы можете инкапсулировать каждую запись в объект, у которого есть методы для повторного извлечения значений. config::getNested('database')->get('default'). В качестве альтернативы, как насчет того, чтобы не вкладывать их, если это возможно? Как насчет того, чтобы разделить их точкой? config::get('database.default')   -  person Dan    schedule 06.02.2012
comment
Это может быть глупый вопрос, но как превратить нотацию database.default в вызов массива?   -  person Lee    schedule 06.02.2012
comment
токенизировать идентификатор и разделить его на точки. если у вас нет точки, это простой вызов, в противном случае возьмите массив в поле с именем первого параметра и поле, указанное параметром за первой точкой и так далее. Если вам нравится идея, я могу опубликовать код в ответе.   -  person Dan    schedule 06.02.2012
comment
Спасибо, Дэн, да, мне нравится идея.. Пример кодирования был бы потрясающим..   -  person Lee    schedule 06.02.2012


Ответы (2)


Как предложено в комментариях, вот код, позволяющий работать с именами, разделенными точками. Может быть более эффективное решение, я просто собрал это для вас.

class Config
{
    private
        $registry
    ;

    public function __construct($registry)
    {
        $this->registry = $registry;
    }

   public function get($identifier)
   {
        return $this->resolve(explode('.', $identifier), $this->registry);
    }

    private function resolve($entries, $in)
    {
        if(key_exists($entries[0], $in) && count($entries) > 1)
        {
            // We have more than one level to resolve
            $newIn = $in[$entries[0]];
            unset($entries[0]);
            return $this->resolve(array_values($entries), $newIn);
        }
        elseif(key_exists($entries[0], $in) && count($entries) == 1)
        {
            // We are at the bottom, let's return.
            return $in[$entries[0]];
        }
        // If we get here something went wrong.
        throw new Exception('Entry could not be resolved.');
    }
}

$cfg = new Config(
    array(
        'plain' => 'plain entry',
        'nested'    =>  array(
            'first' =>  'nested, first entry',
            'second'    =>  array(
                'third' =>  'deeper nested entry'
            )
        )
    )
);

print_r($cfg->get('plain'))."\n";
print_r($cfg->get('nested.first'))."\n";
print_r($cfg->get('nested.second.third'))."\n";
person Dan    schedule 05.02.2012

Если я вас правильно понял, вы можете снова добавить новый экземпляр config, если на следующем уровне есть несколько значений.

Такая конфигурация

value.second = a
value.third = b
other.value.my = a
other.value.foo = b

Это приведет к такому дереву классов (config всегда является экземпляром класса, и намерение означает, что что-то находится в массиве атрибутов экземпляра config выше; тексты перед => являются именами индексов, с которыми вы получите к ним доступ).

config
    value => config
        second => a
        third => b
    other => config
        value => config
            my => a
            foo => b

Надеюсь, вы немного поняли, что я имею в виду.

Затем вы можете реализовать либо ArrayAccess, либо магические методы __get и __set для одного из следующих методы доступа к вашим значениям:

config->value->second
config->other->value->my

or

config['value']['second']
config['other']['value']['my']
person aufziehvogel    schedule 05.02.2012