views:

71

answers:

1

For my project I wrote a small config class that loads its data from a .ini file. It overwrites the magic __get() method in order to provide simplified access to the (read only) config values.

Example config.ini.php:

;<?php exit; ?>
[General]
auth = 1
user = "halfdan"

[Database]
host = "127.0.0.1"

My config class (singleton pattern - simplified here) looks like this:

class Config {
    protected $config = array();

    protected function __construct($file) {
        // Preserve sections
        $this->config = parse_ini_file($file, TRUE);
    }

    public function __get($name) {
        return $this->config[$name];
    }
}

Loading the config would create an array structure like this:

array(
  "General" => array(
    "auth" => 1,
    "user" => "halfdan"
  ),
  "Database" => array(
    "host" => "127.0.0.1"
  )
)

It's possible to access the first level of the array by doing Config::getInstance()->General, and the values using Config::getInstance()->General['user']. What I really want though is being able to access all configuration variables by doing Config::getInstance()->General->user (syntactic sugar). The array is not an object and the "->" isn't defined on it, so this simply fails.

I thought of a solution and would like to get some public opinion about it:

class Config {
  [..]
  public function __get($name) {
    if(is_array($this->config[$name])) {
      return new ConfigArray($this->config[$name]);
    } else {
      return $this->config[$name];
    }
  }
}

class ConfigArray {
  protected $config;

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

  public function __get($name) {
    if(is_array($this->config[$name])) {
      return new ConfigArray($this->config[$name]);
    } else {
      return $this->config[$name];
    }
  }
}

This would allow me to chain my configuration access. As I'm using PHP 5.3 it might also be a good idea to let ConfigArray extend ArrayObject (SPL is activated per default in 5.3).

Any suggestions, improvements, comments?

+1  A: 

If the elements of your $this->config array are also instances of your Config class, then it works.

The Zend Framework has a similar component they call Zend_Config. You can download the source and examine how they implemented it. They didn't have to go all the way to extending ArrayObject.

The Zend_Registry class has similar usage and it does extend ArrayObject. The code for Zend_Registry is somewhat simpler as a result.

Bill Karwin
Looking at Zend_Config::__construct: They do `new self($value, ..)` for deeper array dimensions.
halfdan