Configuration access wrapper class
Configuration access wrapper class
During a chat with a friend about the convenience of object-style access to PHP configuration, which are defined as structured associative arrays, we came to a lightweight wrapper class that addresses these issues. As the configuration array is already in use by other modules, it should not be changed, and a copy to objects would lead to a higher memory usage. So the solution is based on cascaded references to the configuration array. The example shows what it is about:
Während einer kleinen Unterhaltung über "stilistisch gute Erreichbarkeit" von Konfigurationen, die in PHP als verschachtelte assoziative Arrays gespeichert wurden, kamen wir auf eine objektorientierte Lösung mit einer sehr kleinen Wrapper-Klasse. Da das Konfiguration-Array bereits in anderen Modulen verwendet wird, darf es nicht verändert werden, und eine Kopie der Konfiguration als Objektstruktur würde zu einem höheren Speicheraufwand führen. Daher basiert die Lösung auf kaskadierten Referenzen. Das Anwendungsbeispiel zeigt, um was es sich genau handelt:
Sample source code
Anwendungsbeispiel
<?php
// This is an example config array which is e.g. loaded by including
// a config.php or the like.
$theConfigurationStructure = array(
'ref' => 'no',
'database' => array(
'server' => 'unlocalhost',
'user' => 'me',
'password' => 'none',
'database' => 'Example database',
'tables' => array(
'contacts' => array(
'id', 'name', 'email'
),
'cache' => array(
'id', 'uri', 'chksum', 'expires', 'etag', 'lastmodified'
),
)
),
'aNumber' => 10,
'a_text' => 'nothing in there'
);
// This is the instance of the wrapper class, which "points" to
// the root node of the array
$cfg = new ConfigAccess($theConfigurationStructure);
// Access to a scalar config entry
print 'config.aNumber = ' . $cfg->aNumber . '<br/>';
// Access to a scalar config entry in a sub-configuration
print 'config.database.user = ' . $cfg->database->user . '<br/>';
// Access to an array config entry in a sub-configuration
// Note here we have to escape, because the class returns an object
// instead of an array. If we went the array instead, we call the toArray()
// escape function
print 'config.database.tables.cache = ' . print_r($cfg->database->tables->cache->toArray(), true) . '<br/>';
Class source code
Klassen-Quelltext
<?php
/**
* Wrapper class for object-style access to an associative configuration
* array. Note that the configuration keys must be conform to the convention of
* variables (word characters and numbers). Otherwise the array key cannot be
* converted to an object property.
* @class ConfigAccess
* @package de.atwillys.php.misc
* @author Stefan Wilhelm
* @license GPL
*/
class ConfigAccess {
/**
* Reference to the config array content
* @var array
*/
private $__r = null;
/**
* Constructor, stores a reference to the root or sub-branch of the
* assiciative configuration array.
* @param array $cref
*/
public final function __construct(array & $cref) {
$this->__r = &$cref;
}
/**
* Returns the content of the condiguration array (or sub-array) with the
* key $p. If this is an array, then a ConfigAccess object will be returned
* instead, which "points" to the sub-branch of the configuration.
* @param string $p
* @return mixed
*/
public final function __get($p) {
if(!isset($this->__r[$p])) {
throw new Exception("Config entry '$p' does not exist");
}
return is_array($this->__r[$p]) ? new self(&$this->__r[$p]) : $this->__r[$p];
}
/**
* Config setter, this is NOT allowed. Hence, the method throws an exception.
* @param string $p
* @param string $v
*/
public final function __set($p, $v) {
throw new Exception('You cannot modify the configuration');
}
/**
* This method is an escape for the case that the content of a configuration
* is an array and shall not be represented with a ConfigAccess object.
* @return array
*/
public final function toArray() {
return $this->__r;
}
}