Zend_Config Proposal v2.1: Akrabat_Config (7)
There’s been quite a lot of interesting discussion about my Zend_Config proposal this week. As a result it became clear that the method of extension to multiple sections that I chose in Akrabat_Config v0.6 was not what was envisaged.
I wrote up the four choices that I could see for doing inheritence into a post:
Of course, it all depends on what is meant by "nesting" in the comment I've quoted :) It's likely that I have misunderstood, in which case, I'll change the proposal. As I see it the options are: 1. One nest only. i.e. can only extend to one section and that the parent section may not not extend to another section. 2. Single inheritance nesting. i.e. can extend to one section, but that parent section may also extend to a parent section. 3. Multiple inheritance, single depth nesting, i.e. can extend to many sections using comma separated list and each parent section may not extend to another section. 4. Multiple inheritance, multiple depth nesting, i.e. can extend to many sections using comma separated list and each parent section may also extend to another section. My personal preference is for (2) as I feel that (1) may be too limiting, (3) may end up being a debugging nightmare and (4) is a recipe for confusion!
Fortunately Andi agreed with me, so I’ve updated the proposal to v2.1 and Akrabat_Config to v0.7 to support (2) rather than (3).
v2.1 of the Zend_Config proposal is:
Zend Framework Component Proposal Proposed Component Name ----------------------------------------------- Zend_Config Proposers ----------------------------------------------- Rob Allen (rob@akrabat.com Revision ----------------------------------------------- 2.1 - 18 May 2006: Updated following feedback Overview ----------------------------------------------- Zend_Config is a very simple configuration file reader. It provides an easy means to read configuration files and access the data within them as a set of key->value pairs. It will support at least one nested level of data. Initially providing support for ini files, it should be easy to extend for other formats such as YAML. References ----------------------------------------------- Mailing list thread resurrected here: http://www.zend.com/lists/fw-general/200604/msg00178.html. Unfortunately, I could not find the original post by Andi Gutmans in the archives. Other discussion can be found here: http://www.akrabat.com/index.php?s=Akrabat_Config Feedback on v1 from Zend is discussed here: http://www.zend.com/lists/fw-general/200605/msg00134.html Prototype code can be found here: http://www.akrabat.com/2006/05/13/zend_config-proposal-v2/ Mailing list feedback on v2 is discussed here: http://www.zend.com/lists/fw-general/200605/msg00563.html Requirements ----------------------------------------------- * Ability to load configuration information from a single config file and provide access to the data as object properties. * A top level section name must be specified for loading. * Optional option to allow modification of the config data held in memory. * No ability to modify the original data in the config file. * For ini files, support for "namespaces" using the syntax: namespace.property = value * Iterator is implemented for easily listing of configuration information. * A special "inheritence keyword "extends" will be be used to allow for including additional sections within this section. For ini files, the syntax would be: extends = section Dependencies on Other Framework Components ----------------------------------------------- Zend_Exception Theory of Operation ----------------------------------------------- Zend_Config_Abstract provides common functionality for all concrete implementations. It provides the standard retrieval functionality for concrete classes and allows for programmatic setting of config values if $allowModifications has been set to true when the object was created. Zend_Config_Ini is a concrete implementation that loads ini files. It can either load an entire ini file or just a single section. It is possible to load multiple ini files in which case, values for duplicate keys will override the previously loaded value. This is useful to allow for overriding a common config file with context specific data such as for a staging or test server. Zend_Config_Ini also supports using the "."s in a key name to provide additional nesting levels. That is a key named db.name will be represented as $config->db->name. Zend_Config_ini also supports loading of keys from one section of the ini file into another section. This is done using a special key called "extends". It is possible for the parent section to itself extend from another section. Multiple inheritence such that a section can extend from two or more sections is not permitted. In the future, should there be demand for other config file types, a Zend_Config class could be created at a later stage that has a factory function that returns the correct concrete class based on the filename of the config file supplied. For example, myapp.ini would create and return a Zend_Config_Ini object whereas myapp.yml would create and return a Zend_Config_Yaml object. Class Index ----------------------------------------------- Zend_Config_Exception Zend_Config_Abstract Zend_Config_Ini Use Cases ----------------------------------------------- Given the following ini file: [all] namespace.property = example db.connection = foo db.name = bar db.password = pwd hostname = www.zend.com [development] include=all hostname=andi_box db.name=local [andi_development] include=development hostname=andi_box db.connection=localhost [staging] include=all hostname=dev.zend.com Then we can do something like: < ?php $obj=new Zend_Config("myapp.ini", "andi_development"); print $obj->hostname; // prints andi_box print $obj->db->connection; // prints localhost print $obj->db->name; // prints local print $obj->db->password; // prints pwd ?> Class Skeletons ----------------------------------------------- class Zend_Config_Exception extends Zend_Exception {} class Zend_Config_Abstract implements ArrayAccess, IteratorAggregate { protected $_config; protected $_allowModifications; function __construct($filename, $section, $allowModifications=false) {} /** * Load the section $section from the config file $filename. * * If any keys with $section are called "extends", then the section * pointed to by the "extends" is then included into the properties. * Note that the keys in $section will override any keys of the same * name in the sections that have been included via "extends". * * If any key includes a ".", then this will act as a separator to * create a sub-property. * * Only allow modifications after construction if $allowModifications * is set to true. * * @param string $filename * @param string $section * @param boolean $allowModifications */ abstract public function load($filename, $section); /** * Retreive a value from the config key called $name * * @param string $name * @param mixed $default * @return mixed */ public function get($name, $default=null) {} /** * Does the config key $name exist? * * @param string $name * @return boolean */ public function exists($name) {} /** * magic function so that $obj->value will work. * * @param string $name * @return mixed */ public function __get($name) {} /** * Only allow setting of a property if allowModifications * is true. Otherwise, throw an exception. * * @param string $name * @param mixed $value */ public function __set($name, $value) {} } class Zend_Config_Ini extends Zend_Config_Abstract { /** * Load $section from an ini file called $filename. * * @param string $filename * @param string $section */ public function load($filename, $section) {} /** * Helper function to process each element in the section and handle * the "extends" inheritance keyword. Passes control to processKey() * to handle the "dot" sub-property syntax in each key. * * @param array $iniArray * @param string $section * @return array */ protected function processExtends($iniArray, $section) {} /** * Assign the key's value to the property list. Handle the "dot" * notation for sub-properties by passing control to * processLevelsInKey(). * * @param stdClass $config * @param string $key * @param string $value * @return stdClass */ function processKey($config, $key , $value) {} /** * Helper function to handle the "dot" namespace syntax in the key. * Uses "." as the separator. * * @param stdClass $parent * @param string $key * @param string $value * @return stdClass */ protected function processLevelsInKey($parent, $key, $value) {} }
And v0.7 of Akrabat_Config implements this spec. Again, I’ve put both the code and tests into a single zip file: Akrabat_Config 0.7.
As always, thoughts and corrections welcome!
Ahh I much prefer the single inheritance nesting :)
I've always found multiple level inheritance tough to work with…
Thanks for the hard work so far !
Steven