a00c976f11c506042c804f39a67c1388c7a224c8
6 * @author Michael Wallner <mike@php.net>
11 * A merry config container
13 * @see https://github.com/m6w6/merry
14 * @package merry\Config
16 class Config
implements \ArrayAccess
, \RecursiveIterator
19 * Index for a numerically indexed array
33 * State for the RecursiveIterator
40 * Create a new configuration container
41 * @param array $array the configuration array
42 * @param string $section the section to use (i.e. first level key)
43 * @param string $section_sep a separator for section extension
44 * @param string $key_sep a separator for key traversal
46 public function __construct(array $array = null, $section = null, $section_sep = ":", $key_sep = ".") {
47 $this->props
= new \stdClass
;
49 if (isset($section) && strlen($section_sep)) {
50 $array = $this->combine($array, $section_sep)[$section];
55 if (strlen($key_sep)) {
56 foreach ($array as $key => $val) {
57 $this->walk($config, $key, $val, $key_sep);
61 foreach ($config as $property => $value) {
62 $this->__set($property, $value);
68 * Combine individual sections with their parent section
69 * @param array $array the config array
70 * @param string $section_sep the section extension separator
71 * @return array merged sections
73 protected function combine($array, $section_sep) {
74 foreach ($array as $section_spec => $settings) {
75 $section_spec = array_map("trim", explode($section_sep, $section_spec));
76 if (count($section_spec) > 1) {
77 $sections[$section_spec[0]] = array_merge(
78 $sections[$section_spec[1]],
82 $sections[$section_spec[0]] = $settings;
89 * Walk a key split by the key separator into an array up and set the
90 * respective value on the leaf
91 * @param mixed $ptr current leaf pointer in the array
92 * @param string $key the array key
93 * @param mixed $val the value to set
94 * @param string $key_sep the key separator for traversal
96 protected function walk(&$ptr, $key, $val, $key_sep) {
97 foreach (explode($key_sep, $key) as $sub) {
104 * Recursively turn a Config instance and its childs into an array
105 * @param \merry\Config $o the Config instance to convert to an array
108 protected function arrayify(Config
$o) {
111 foreach ($o->props
as $k => $v) {
112 if ($v instanceof Config
) {
113 $a[$k] = $this->arrayify($v);
123 * Apply one or mor modifier callbacks
124 * @param mixed $modifier
125 * @return \merry\Config
127 public function apply($modifier) {
128 if (is_callable($modifier)) {
129 foreach ($this->props
as $prop => $value) {
130 $this->__set($prop, $modifier($value, $prop));
133 foreach ($modifier as $key => $mod) {
134 if (is_callable($mod)) {
135 $this->props
->$key = $mod(isset($this->props
->$key) ?
$this->props
->$key : null, $key);
136 } elseif (is_array($mod)) {
137 $this->props
->$key->apply($mod);
147 * Return the complete config as array
151 return $this->arrayify($this);
157 function __get($prop) {
158 return $this->props
->$prop;
164 function __set($prop, $value) {
165 if (isset($value) && !is_scalar($value) && !($value instanceof Config
)) {
166 $value = new static((array) $value);
168 if (!strlen($prop)) {
169 $prop = $this->index++
;
170 } elseif (is_numeric($prop) && !strcmp($prop, (int) $prop)) {
171 /* update internal index */
172 if ($prop >= $this->index
) {
173 $this->index
= $prop +
1;
177 $this->props
->$prop = $value;
183 function __isset($prop) {
184 return isset($this->props
->$prop);
190 function __unset($prop) {
191 unset($this->props
->$prop);
197 function offsetGet($o) {
198 return $this->props
->$o;
204 function offsetSet($o, $v) {
205 $this->__set($o, $v);
211 function offsetExists($o) {
212 return isset($this->props
->$o);
218 function offsetUnset($o) {
219 unset($this->props
->$o);
226 $this->riter
= (array) $this->props
;
234 return NULL !== key($this->riter
);
248 return key($this->riter
);
255 return current($this->riter
);
261 function hasChildren() {
262 return current($this->riter
) instanceof Config
;
268 function getChildren() {
269 return current($this->riter
);