PageRenderTime 27ms CodeModel.GetById 21ms RepoModel.GetById 0ms app.codeStats 0ms

/library/Zend/Config/Config.php

http://github.com/zendframework/zf2
PHP | 386 lines | 170 code | 36 blank | 180 comment | 24 complexity | 48904642d79d053766f3c8f766f159d8 MD5 | raw file
Possible License(s): BSD-3-Clause
  1. <?php
  2. /**
  3. * Zend Framework (http://framework.zend.com/)
  4. *
  5. * @link http://github.com/zendframework/zf2 for the canonical source repository
  6. * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
  7. * @license http://framework.zend.com/license/new-bsd New BSD License
  8. */
  9. namespace Zend\Config;
  10. use ArrayAccess;
  11. use Countable;
  12. use Iterator;
  13. /**
  14. * Provides a property based interface to an array.
  15. * The data are read-only unless $allowModifications is set to true
  16. * on construction.
  17. *
  18. * Implements Countable, Iterator and ArrayAccess
  19. * to facilitate easy access to the data.
  20. */
  21. class Config implements Countable, Iterator, ArrayAccess
  22. {
  23. /**
  24. * Whether modifications to configuration data are allowed.
  25. *
  26. * @var bool
  27. */
  28. protected $allowModifications;
  29. /**
  30. * Data within the configuration.
  31. *
  32. * @var array
  33. */
  34. protected $data = array();
  35. /**
  36. * Used when unsetting values during iteration to ensure we do not skip
  37. * the next element.
  38. *
  39. * @var bool
  40. */
  41. protected $skipNextIteration;
  42. /**
  43. * Constructor.
  44. *
  45. * Data is read-only unless $allowModifications is set to true
  46. * on construction.
  47. *
  48. * @param array $array
  49. * @param bool $allowModifications
  50. */
  51. public function __construct(array $array, $allowModifications = false)
  52. {
  53. $this->allowModifications = (bool) $allowModifications;
  54. foreach ($array as $key => $value) {
  55. if (is_array($value)) {
  56. $this->data[$key] = new static($value, $this->allowModifications);
  57. } else {
  58. $this->data[$key] = $value;
  59. }
  60. }
  61. }
  62. /**
  63. * Retrieve a value and return $default if there is no element set.
  64. *
  65. * @param string $name
  66. * @param mixed $default
  67. * @return mixed
  68. */
  69. public function get($name, $default = null)
  70. {
  71. if (array_key_exists($name, $this->data)) {
  72. return $this->data[$name];
  73. }
  74. return $default;
  75. }
  76. /**
  77. * Magic function so that $obj->value will work.
  78. *
  79. * @param string $name
  80. * @return mixed
  81. */
  82. public function __get($name)
  83. {
  84. return $this->get($name);
  85. }
  86. /**
  87. * Set a value in the config.
  88. *
  89. * Only allow setting of a property if $allowModifications was set to true
  90. * on construction. Otherwise, throw an exception.
  91. *
  92. * @param string $name
  93. * @param mixed $value
  94. * @return void
  95. * @throws Exception\RuntimeException
  96. */
  97. public function __set($name, $value)
  98. {
  99. if ($this->allowModifications) {
  100. if (is_array($value)) {
  101. $value = new static($value, true);
  102. }
  103. if (null === $name) {
  104. $this->data[] = $value;
  105. } else {
  106. $this->data[$name] = $value;
  107. }
  108. } else {
  109. throw new Exception\RuntimeException('Config is read only');
  110. }
  111. }
  112. /**
  113. * Deep clone of this instance to ensure that nested Zend\Configs are also
  114. * cloned.
  115. *
  116. * @return void
  117. */
  118. public function __clone()
  119. {
  120. $array = array();
  121. foreach ($this->data as $key => $value) {
  122. if ($value instanceof self) {
  123. $array[$key] = clone $value;
  124. } else {
  125. $array[$key] = $value;
  126. }
  127. }
  128. $this->data = $array;
  129. }
  130. /**
  131. * Return an associative array of the stored data.
  132. *
  133. * @return array
  134. */
  135. public function toArray()
  136. {
  137. $array = array();
  138. $data = $this->data;
  139. /** @var self $value */
  140. foreach ($data as $key => $value) {
  141. if ($value instanceof self) {
  142. $array[$key] = $value->toArray();
  143. } else {
  144. $array[$key] = $value;
  145. }
  146. }
  147. return $array;
  148. }
  149. /**
  150. * isset() overloading
  151. *
  152. * @param string $name
  153. * @return bool
  154. */
  155. public function __isset($name)
  156. {
  157. return isset($this->data[$name]);
  158. }
  159. /**
  160. * unset() overloading
  161. *
  162. * @param string $name
  163. * @return void
  164. * @throws Exception\InvalidArgumentException
  165. */
  166. public function __unset($name)
  167. {
  168. if (!$this->allowModifications) {
  169. throw new Exception\InvalidArgumentException('Config is read only');
  170. } elseif (isset($this->data[$name])) {
  171. unset($this->data[$name]);
  172. $this->skipNextIteration = true;
  173. }
  174. }
  175. /**
  176. * count(): defined by Countable interface.
  177. *
  178. * @see Countable::count()
  179. * @return int
  180. */
  181. public function count()
  182. {
  183. return count($this->data);
  184. }
  185. /**
  186. * current(): defined by Iterator interface.
  187. *
  188. * @see Iterator::current()
  189. * @return mixed
  190. */
  191. public function current()
  192. {
  193. $this->skipNextIteration = false;
  194. return current($this->data);
  195. }
  196. /**
  197. * key(): defined by Iterator interface.
  198. *
  199. * @see Iterator::key()
  200. * @return mixed
  201. */
  202. public function key()
  203. {
  204. return key($this->data);
  205. }
  206. /**
  207. * next(): defined by Iterator interface.
  208. *
  209. * @see Iterator::next()
  210. * @return void
  211. */
  212. public function next()
  213. {
  214. if ($this->skipNextIteration) {
  215. $this->skipNextIteration = false;
  216. return;
  217. }
  218. next($this->data);
  219. }
  220. /**
  221. * rewind(): defined by Iterator interface.
  222. *
  223. * @see Iterator::rewind()
  224. * @return void
  225. */
  226. public function rewind()
  227. {
  228. $this->skipNextIteration = false;
  229. reset($this->data);
  230. }
  231. /**
  232. * valid(): defined by Iterator interface.
  233. *
  234. * @see Iterator::valid()
  235. * @return bool
  236. */
  237. public function valid()
  238. {
  239. return ($this->key() !== null);
  240. }
  241. /**
  242. * offsetExists(): defined by ArrayAccess interface.
  243. *
  244. * @see ArrayAccess::offsetExists()
  245. * @param mixed $offset
  246. * @return bool
  247. */
  248. public function offsetExists($offset)
  249. {
  250. return $this->__isset($offset);
  251. }
  252. /**
  253. * offsetGet(): defined by ArrayAccess interface.
  254. *
  255. * @see ArrayAccess::offsetGet()
  256. * @param mixed $offset
  257. * @return mixed
  258. */
  259. public function offsetGet($offset)
  260. {
  261. return $this->__get($offset);
  262. }
  263. /**
  264. * offsetSet(): defined by ArrayAccess interface.
  265. *
  266. * @see ArrayAccess::offsetSet()
  267. * @param mixed $offset
  268. * @param mixed $value
  269. * @return void
  270. */
  271. public function offsetSet($offset, $value)
  272. {
  273. $this->__set($offset, $value);
  274. }
  275. /**
  276. * offsetUnset(): defined by ArrayAccess interface.
  277. *
  278. * @see ArrayAccess::offsetUnset()
  279. * @param mixed $offset
  280. * @return void
  281. */
  282. public function offsetUnset($offset)
  283. {
  284. $this->__unset($offset);
  285. }
  286. /**
  287. * Merge another Config with this one.
  288. *
  289. * For duplicate keys, the following will be performed:
  290. * - Nested Configs will be recursively merged.
  291. * - Items in $merge with INTEGER keys will be appended.
  292. * - Items in $merge with STRING keys will overwrite current values.
  293. *
  294. * @param Config $merge
  295. * @return Config
  296. */
  297. public function merge(Config $merge)
  298. {
  299. /** @var Config $value */
  300. foreach ($merge as $key => $value) {
  301. if (array_key_exists($key, $this->data)) {
  302. if (is_int($key)) {
  303. $this->data[] = $value;
  304. } elseif ($value instanceof self && $this->data[$key] instanceof self) {
  305. $this->data[$key]->merge($value);
  306. } else {
  307. if ($value instanceof self) {
  308. $this->data[$key] = new static($value->toArray(), $this->allowModifications);
  309. } else {
  310. $this->data[$key] = $value;
  311. }
  312. }
  313. } else {
  314. if ($value instanceof self) {
  315. $this->data[$key] = new static($value->toArray(), $this->allowModifications);
  316. } else {
  317. $this->data[$key] = $value;
  318. }
  319. }
  320. }
  321. return $this;
  322. }
  323. /**
  324. * Prevent any more modifications being made to this instance.
  325. *
  326. * Useful after merge() has been used to merge multiple Config objects
  327. * into one object which should then not be modified again.
  328. *
  329. * @return void
  330. */
  331. public function setReadOnly()
  332. {
  333. $this->allowModifications = false;
  334. /** @var Config $value */
  335. foreach ($this->data as $value) {
  336. if ($value instanceof self) {
  337. $value->setReadOnly();
  338. }
  339. }
  340. }
  341. /**
  342. * Returns whether this Config object is read only or not.
  343. *
  344. * @return bool
  345. */
  346. public function isReadOnly()
  347. {
  348. return !$this->allowModifications;
  349. }
  350. }