7 * This source file is subject to the new BSD license that is bundled
8 * with this package in the file LICENSE.txt.
9 * It is also available through the world-wide-web at this URL:
10 * http://framework.zend.com/license/new-bsd
11 * If you did not receive a copy of the license and are unable to
12 * obtain it through the world-wide-web, please send an email
13 * to license@zend.com so we can send you a copy immediately.
16 * @package Zend_Config
17 * @copyright Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com)
18 * @license http://framework.zend.com/license/new-bsd New BSD License
25 * @package Zend_Config
26 * @copyright Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com)
27 * @license http://framework.zend.com/license/new-bsd New BSD License
29 class Zend_Config
implements Countable
, Iterator
32 * Whether in-memory modifications to configuration data are allowed
36 protected $_allowModifications;
46 * Number of elements in configuration data
53 * Contains array of configuration data
60 * Used when unsetting values during iteration to ensure we do not skip
65 protected $_skipNextIteration;
68 * Contains which config file sections were loaded. This is null
69 * if all sections were loaded, a string name if one section is loaded
70 * and an array of string names if multiple sections were loaded.
74 protected $_loadedSection;
77 * This is used to track section inheritance. The keys are names of sections that
78 * extend other sections, and the values are the extended sections.
82 protected $_extends = array();
85 * Load file error string.
87 * Is null if there was no error while file loading
91 protected $_loadFileErrorStr = null;
94 * Zend_Config provides a property based interface to
95 * an array. The data are read-only unless $allowModifications
96 * is set to true on construction.
98 * Zend_Config also implements Countable and Iterator to
99 * facilitate easy access to the data.
101 * @param array $array
102 * @param boolean $allowModifications
105 public function __construct(array $array, $allowModifications = false)
107 $this->_allowModifications
= (boolean
) $allowModifications;
108 $this->_loadedSection
= null;
110 $this->_data
= array();
111 foreach ($array as $key => $value) {
112 if (is_array($value)) {
113 $this->_data
[$key] = new self($value, $this->_allowModifications
);
115 $this->_data
[$key] = $value;
118 $this->_count
= count($this->_data
);
122 * Retrieve a value and return $default if there is no element set.
124 * @param string $name
125 * @param mixed $default
128 public function get($name, $default = null)
131 if (array_key_exists($name, $this->_data
)) {
132 $result = $this->_data
[$name];
138 * Magic function so that $obj->value will work.
140 * @param string $name
143 public function __get($name)
145 return $this->get($name);
149 * Only allow setting of a property if $allowModifications
150 * was set to true on construction. Otherwise, throw an exception.
152 * @param string $name
153 * @param mixed $value
154 * @throws Zend_Config_Exception
157 public function __set($name, $value)
159 if ($this->_allowModifications
) {
160 if (is_array($value)) {
161 $this->_data
[$name] = new self($value, true);
163 $this->_data
[$name] = $value;
165 $this->_count
= count($this->_data
);
167 /** @see Zend_Config_Exception */
168 require_once 'Zend/Config/Exception.php';
169 throw new Zend_Config_Exception('Zend_Config is read only');
174 * Deep clone of this instance to ensure that nested Zend_Configs
179 public function __clone()
182 foreach ($this->_data
as $key => $value) {
183 if ($value instanceof Zend_Config
) {
184 $array[$key] = clone $value;
186 $array[$key] = $value;
189 $this->_data
= $array;
193 * Return an associative array of the stored data.
197 public function toArray()
200 $data = $this->_data
;
201 foreach ($data as $key => $value) {
202 if ($value instanceof Zend_Config
) {
203 $array[$key] = $value->toArray();
205 $array[$key] = $value;
212 * Support isset() overloading on PHP 5.1
214 * @param string $name
217 public function __isset($name)
219 return isset($this->_data
[$name]);
223 * Support unset() overloading on PHP 5.1
225 * @param string $name
226 * @throws Zend_Config_Exception
229 public function __unset($name)
231 if ($this->_allowModifications
) {
232 unset($this->_data
[$name]);
233 $this->_count
= count($this->_data
);
234 $this->_skipNextIteration
= true;
236 /** @see Zend_Config_Exception */
237 require_once 'Zend/Config/Exception.php';
238 throw new Zend_Config_Exception('Zend_Config is read only');
244 * Defined by Countable interface
248 public function count()
250 return $this->_count
;
254 * Defined by Iterator interface
258 public function current()
260 $this->_skipNextIteration
= false;
261 return current($this->_data
);
265 * Defined by Iterator interface
269 public function key()
271 return key($this->_data
);
275 * Defined by Iterator interface
278 public function next()
280 if ($this->_skipNextIteration
) {
281 $this->_skipNextIteration
= false;
289 * Defined by Iterator interface
292 public function rewind()
294 $this->_skipNextIteration
= false;
300 * Defined by Iterator interface
304 public function valid()
306 return $this->_index
< $this->_count
;
310 * Returns the section name(s) loaded.
314 public function getSectionName()
316 if(is_array($this->_loadedSection
) && count($this->_loadedSection
) == 1) {
317 $this->_loadedSection
= $this->_loadedSection
[0];
319 return $this->_loadedSection
;
323 * Returns true if all sections were loaded
327 public function areAllSectionsLoaded()
329 return $this->_loadedSection
=== null;
334 * Merge another Zend_Config with this one. The items
335 * in $merge will override the same named items in
336 * the current config.
338 * @param Zend_Config $merge
339 * @return Zend_Config
341 public function merge(Zend_Config
$merge)
343 foreach($merge as $key => $item) {
344 if(array_key_exists($key, $this->_data
)) {
345 if($item instanceof Zend_Config
&& $this->$key instanceof Zend_Config
) {
346 $this->$key = $this->$key->merge(new Zend_Config($item->toArray(), !$this->readOnly()));
351 if($item instanceof Zend_Config
) {
352 $this->$key = new Zend_Config($item->toArray(), !$this->readOnly());
363 * Prevent any more modifications being made to this instance. Useful
364 * after merge() has been used to merge multiple Zend_Config objects
365 * into one object which should then not be modified again.
368 public function setReadOnly()
370 $this->_allowModifications
= false;
371 foreach ($this->_data
as $key => $value) {
372 if ($value instanceof Zend_Config
) {
373 $value->setReadOnly();
379 * Returns if this Zend_Config object is read only or not.
383 public function readOnly()
385 return !$this->_allowModifications
;
389 * Get the current extends
393 public function getExtends()
395 return $this->_extends
;
399 * Set an extend for Zend_Config_Writer
401 * @param string $extendingSection
402 * @param string $extendedSection
405 public function setExtend($extendingSection, $extendedSection = null)
407 if ($extendedSection === null && isset($this->_extends
[$extendingSection])) {
408 unset($this->_extends
[$extendingSection]);
409 } else if ($extendedSection !== null) {
410 $this->_extends
[$extendingSection] = $extendedSection;
415 * Throws an exception if $extendingSection may not extend $extendedSection,
416 * and tracks the section extension if it is valid.
418 * @param string $extendingSection
419 * @param string $extendedSection
420 * @throws Zend_Config_Exception
423 protected function _assertValidExtend($extendingSection, $extendedSection)
425 // detect circular section inheritance
426 $extendedSectionCurrent = $extendedSection;
427 while (array_key_exists($extendedSectionCurrent, $this->_extends
)) {
428 if ($this->_extends
[$extendedSectionCurrent] == $extendingSection) {
429 /** @see Zend_Config_Exception */
430 require_once 'Zend/Config/Exception.php';
431 throw new Zend_Config_Exception('Illegal circular inheritance detected');
433 $extendedSectionCurrent = $this->_extends
[$extendedSectionCurrent];
435 // remember that this section extends another section
436 $this->_extends
[$extendingSection] = $extendedSection;
440 * Handle any errors from simplexml_load_file or parse_ini_file
442 * @param integer $errno
443 * @param string $errstr
444 * @param string $errfile
445 * @param integer $errline
447 protected function _loadFileErrorHandler($errno, $errstr, $errfile, $errline)
449 if ($this->_loadFileErrorStr
=== null) {
450 $this->_loadFileErrorStr
= $errstr;
452 $this->_loadFileErrorStr
.= (PHP_EOL
. $errstr);
457 * Merge two arrays recursively, overwriting keys of the same name
458 * in $firstArray with the value in $secondArray.
460 * @param mixed $firstArray First array
461 * @param mixed $secondArray Second array to merge into first array
464 protected function _arrayMergeRecursive($firstArray, $secondArray)
466 if (is_array($firstArray) && is_array($secondArray)) {
467 foreach ($secondArray as $key => $value) {
468 if (isset($firstArray[$key])) {
469 $firstArray[$key] = $this->_arrayMergeRecursive($firstArray[$key], $value);
472 $firstArray= array(0=>$this->_arrayMergeRecursive($firstArray, $value));
474 $firstArray[$key] = $value;
479 $firstArray = $secondArray;