Lee
Lee

Reputation: 5936

Config registry - how to implement

I am after some input/guidance.. I have an application that uses a central configuration registry as show below..

The application parses a config directory for ini files and sets the arrays into the class using the name of the file as the index, as well as single configuration variables when required..

I can see a few problems arising including:

  1. Name clashes between files and vars set within the script
  2. The inability to pull nested array variables resulting in the following code:

    $databases = config::get('database'); $actual_record = $databases['default'];

I was tempted to add a 2nd get parameter for the nested value, however what happens in the future if i need to pull a 3rd or 4th level value.

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;
   }
}

Thanks in advance for the help..

Upvotes: 1

Views: 641

Answers (2)

Dan
Dan

Reputation: 1888

As proposed in the comments here is the code to make the dot separated names working. There might be a more efficient solution, I just threw this together for you.

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";

Upvotes: 1

aufziehvogel
aufziehvogel

Reputation: 7297

If I understand you correctly you could add a new instance of config again if there are multiple values on the next level.

A configuration like this

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

Would then result in a class tree like this (config always is an instance of the class and intendation means that something is in the attributes array of the config instance above; texts before the => are index names, with which you will access them).

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

I hope you can grasp a bit what I mean.

Then you could implement either ArrayAccess or magic methods __get and __set for one of the following methods to access your values:

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

or

config['value']['second']
config['other']['value']['my']

Upvotes: 2

Related Questions