Akrabat_Config (2nd Attempt)
Update! This version has been superceded! Check out Akrabat_Config (Take Three!) for an even better version…
Nico Edtinger was kind enough to review Akrabat_Config and pointed out that it wouldn't handle a key with multiple dots in it. His post to fw-general:
One method I don't "like" is processSection(). If I have a name like "foo.bar.baz" it would be saved as $config['foo']['bar'], dropping the last part because you explode without a third parameter. It should be
$pieces = explode('.', $key, 2);I'd also change the check for a dot to
if(strpos($key, '.')) {That would work with a key with a leading dot (being stored just as is instead of $config[''][...]) and the explode doesn't need to parse a string that doesn't have a dot anyway and create an array that's not needed.
Thus, this is my second attempt at Akrabat_Config:
The new tests are:
<?php require_once 'PHPUnit2/Framework/TestCase.php'; include "Zend.php"; class ConfigTest extends PHPUnit2_Framework_TestCase { protected $iniFilename; function setUp() { $this->iniFilename = dirname(__FILE__).'/data/config.ini'; } function testLoadAll() { Zend::loadClass('Akrabat_Config'); $config = new Akrabat_Config($this->iniFilename, 'all'); $this->assertEquals('all', $config->hostname); $this->assertEquals('all', $config->test['me']); } function testInclude() { Zend::loadClass('Akrabat_Config'); $config = new Akrabat_Config($this->iniFilename, 'staging'); $this->assertEquals('staging', $config->hostname); $this->assertEquals('staging', $config->test['me']); } function testMultiLevels() { Zend::loadClass('Akrabat_Config'); $config = new Akrabat_Config($this->iniFilename, 'multi'); zend::dump($config); $this->assertEquals('four', $config->one['two.three']); $this->assertEquals('five', $config->one['two.three.four']); } function testLeadingDot() { Zend::loadClass('Akrabat_Config'); $config = new Akrabat_Config($this->iniFilename, 'dot'); $this->assertEquals('dot', $config->get(".")); $this->assertEquals('doubledot', $config->get("..")); $this->assertEquals('t-dot', $config->get("t.")); $this->assertEquals('dot-t', $config->get(".t")); } } ?>
with data/config.ini:
[all] hostname = all test.me = all [staging] include = all hostname = staging test.me = staging [multi] one.two.three = four one.two.three.four = five one.two..three = dotdotthree [dot] . = dot .. = doubledot t. = t-dot .t = dot-t
and Akrabat_Config looks like this:
<?php class Akrabat_Config { private $_config; /** * Load the section $section from the ini file called $filename. * If any keys with $section are called "include", then the section * pointed to by the "include" is then included first. Thus, the keys * in $section will override any keys of the same name in the sections * that have been "include"ed. * * example ini file: * [all] * db.connection = database * hostname = live * * [staging] * include = all * hostname = staging * * after callgin $config = new Akrabat_Config($file, 'staging'); then * $config->hostname = staging * $config->db['connection'] = database * * * @param string $filename * @param string $section */ function __construct($filename, $section) { $iniArray = parse_ini_file($filename, true); $config = array(); if(isset($iniArray[$section])) { foreach($iniArray[$section] as $key => $value) { if($key == 'include') { if(isset($iniArray[$value])) { $config = array_merge($config, $this->processSection($iniArray[$value])); } unset($iniArray[$section][$key]); } } $config = array_merge($config, $this->processSection($iniArray[$section])); } else { throw new Exception("No section '$section' in $filename'"); } $this->_config = $config; } /** * Helper function to handle single level namespace in the key * * @param array $section * @return array */ protected function processSection($section) { $config = array(); foreach($section as $key=>$value) { if(strpos($key, '.')) { $pieces = explode('.', $key, 2); if(!empty($pieces[1])) { $config[$pieces[0]][$pieces[1]] = $value; } else { $config[$key] = $value; } } else { $config[$key] = $value; } } return $config; } /** * @param string $name * @param mixed $default * @return mixed */ function get($name, $default=false) { $result = $default; if(isset($this->_config[$name])) { $result = $this->_config[$name]; } return $result; } /** * magic function so that $config->value will work. * * @param string $name * @return mixed */ function __get($name) { return $this->get($name); } } ?>

April 8th, 2006 at 13:10 #
Looks interesting. I've always hated to have my settings all over the place. It's also something that I don't like in my bootstap file. It's clutter ;) Then again, there ini functions in PHP if i'm not mistaken, so this could be considered reinventing the wheel…
April 8th, 2006 at 16:15 #
Yes - this class is a thin wrapper around the ini handling function. Though it provides additional functionality by allowing for overriding of keys in one section with keys in another.
On the fw-general list we are talking about allowing for loading multiple files into one config object. I quite like that idea so might play with it tonight.