/php/struct/Traversor.php

https://bitbucket.org/emilhdiaz/webics · PHP · 538 lines · 222 code · 57 blank · 259 comment · 15 complexity · 30e5ff038c3d431e0a96dddab3e6a5dc MD5 · raw file

  1. <?php
  2. /*
  3. * Traversor uses the Adapter Pattern to provide a
  4. * unified interface to PHP's array functions. All functions
  5. * declared in this class must preserve array keys.
  6. */
  7. abstract class Traversor extends Object implements Iterable, Iterator, ArrayAccess {
  8. protected $var = array();
  9. const nativeType = 'array';
  10. /**
  11. * The Traversor will store any structure that implements
  12. * the Iterator Interface in a natural PHP associated array.
  13. *
  14. * @param Iterator $struct
  15. * @return self
  16. * @access public
  17. */
  18. public function __construct( $struct = null ) {
  19. parent::__construct();
  20. $struct = static::validate($struct);
  21. foreach($struct as $key => $value ) {
  22. $this->var[$key] = $value;
  23. }
  24. }
  25. /**
  26. * Get values by key. To access numeric
  27. * keys enclose the number with brackets{}.
  28. *
  29. * @magic
  30. * @param scalar $key
  31. * @return mixed
  32. * @access public
  33. */
  34. public function __get( $key ) {
  35. if( !$this->hasKey($key) ) throw new InvalidIndexException($key);
  36. return $this->var[$key];
  37. }
  38. /**
  39. * Set values by key. To access numeric
  40. * keys enclose the number with brackets{}.
  41. *
  42. * @magic
  43. * @param scalar $key
  44. * @param mixed $value
  45. * @access public
  46. */
  47. public function __set( $key, $value ) {
  48. $this->var[$key] = $value;
  49. }
  50. public function __isset( $name ) {
  51. return isset($this->var[$name]);
  52. }
  53. public function __clone() {
  54. foreach( $this->var as &$element ) {
  55. if( is_object($element) )
  56. $element = clone $element;
  57. else
  58. $element = $element;
  59. }
  60. }
  61. public function __toString() {
  62. $array = array();
  63. foreach( $this->var as $key=>$var ) {
  64. $array[] = $key.' = '.$var;
  65. }
  66. return '('.implode(', ',$array).')';
  67. }
  68. public function __toArray() {
  69. $elements = array();
  70. foreach( $this->var as $key => &$element ) {
  71. if( $element instanceOf Iterable ) {
  72. $elements[$key] = $element->__toArray();
  73. }
  74. else
  75. $elements[$key] = $element;
  76. }
  77. return $elements;
  78. }
  79. public function __toVArray() {
  80. return new VArray(array_values($this->var));
  81. }
  82. public function __toHash() {
  83. return new Hash($this->var);
  84. }
  85. public function get( $key, $default = null ) {
  86. return $this->hasKey($key) ? $this->var[$key] : $default;
  87. }
  88. public function iterator() {
  89. $iterator = new static;
  90. foreach( $this->var as $key => $element ) {
  91. if( $element instanceOf Iterable ) {
  92. $iterator->$key = $element->iterator();
  93. }
  94. else
  95. $iterator->$key = $element;
  96. }
  97. return $iterator;
  98. }
  99. /**
  100. * Return the natural PHP associated array representation of the
  101. * stored data.
  102. *
  103. * @param void
  104. * @return array
  105. * @access public
  106. */
  107. public function arr() {
  108. return $this->var;
  109. }
  110. /**
  111. * Return the values of the array.
  112. *
  113. * @param void
  114. * @return self
  115. * @access public
  116. */
  117. public function values() {
  118. return new VArray(array_values($this->var));
  119. }
  120. /**
  121. * Return the keys of the array.
  122. *
  123. * @param void
  124. * @return self
  125. * @access public
  126. */
  127. public function keys() {
  128. return new VArray(array_keys($this->var));
  129. }
  130. /**
  131. * Return the current value.
  132. *
  133. * @param void
  134. * @return mixed
  135. * @access public
  136. */
  137. public function &current() {
  138. return current($this->var);
  139. }
  140. /**
  141. * Return the key of the current value.
  142. *
  143. * @param void
  144. * @return scalar
  145. * @access public
  146. */
  147. public function key() {
  148. return key($this->var);
  149. }
  150. /**
  151. * Return the first element of the array.
  152. *
  153. * @param void
  154. * @return mixed
  155. * @access public
  156. */
  157. public function &first() {
  158. return reset($this->var);
  159. }
  160. /**
  161. * Return the last element of the array.
  162. *
  163. * @param void
  164. * @return mixed
  165. * @access public
  166. */
  167. public function &last() {
  168. return end($this->var);
  169. }
  170. /**
  171. * Return the next element of the array.
  172. *
  173. * @param void
  174. * @return mixed
  175. * @access public
  176. */
  177. public function &next() {
  178. return next($this->var);
  179. }
  180. /**
  181. * Return the previous element of the array.
  182. *
  183. * @param void
  184. * @return mixed
  185. * @access public
  186. */
  187. public function &prev() {
  188. return prev($this->var);
  189. }
  190. /**
  191. * Check if the pointer is not out of bounds.
  192. *
  193. * @param void
  194. * @return boolean
  195. * @access public
  196. */
  197. public function valid() {
  198. return $var = $this->current() !== false;
  199. }
  200. /**
  201. * Reset the array pointer.
  202. *
  203. * @param void
  204. * @return void
  205. * @access public
  206. */
  207. public function rewind() {
  208. reset($this->var);
  209. }
  210. public function offsetExists( $offset ) {
  211. return isset( $this->var[$offset] );
  212. }
  213. public function offsetSet( $offset, $value) {
  214. if( $offset )
  215. $this->var[$offset] = $value;
  216. else
  217. $this->var[] = $value;
  218. }
  219. public function offsetGet( $offset ) {
  220. return $this->var[$offset];
  221. }
  222. public function offsetUnset( $offset ) {
  223. unset( $this->var[$offset] );
  224. }
  225. /**
  226. * Return a random element from the array.
  227. *
  228. * @param void
  229. * @return mixed
  230. * @access public
  231. */
  232. public function random() {
  233. return $this->var[array_rand($this->var)];
  234. }
  235. /**
  236. * Return the number of elements in the array.
  237. *
  238. * @param void
  239. * @return integer
  240. * @access public
  241. */
  242. public function size() {
  243. return count($this->var);
  244. }
  245. /**
  246. * Check if a value exist.
  247. *
  248. * @param mixed $value
  249. * @return boolean
  250. * @access public
  251. */
  252. public function hasValue( $value ) {
  253. return in_array($value, $this->var);
  254. }
  255. /**
  256. * Check if a key exist.
  257. *
  258. * @param scalar $key
  259. * @return boolean
  260. * @access public
  261. */
  262. public function hasKey( $key ) {
  263. return array_key_exists($key, $this->var);
  264. }
  265. /**
  266. * Determines the structure of the data set
  267. *
  268. * @return string
  269. * @access public
  270. */
  271. public function structure() {
  272. $structure = null;
  273. foreach( $this->var as $element ) {
  274. if( (is_array($element) || $element instanceOf Iterable) )
  275. if( $structure == 'single')
  276. $structure = 'mixed';
  277. else
  278. $structure = 'multi';
  279. else
  280. if( $structure == 'multi')
  281. $structure = 'mixed';
  282. else
  283. $structure = 'single';
  284. }
  285. return $structure;
  286. }
  287. /**
  288. * Implodes the values of the data set into a string
  289. * using a delimiter.
  290. *
  291. * @param string $delimiter
  292. * @return string
  293. * @access public
  294. */
  295. public function join( $delimiter ) {
  296. return new String(implode($delimiter, $this->var));
  297. }
  298. /**
  299. * Return the key found using a value.
  300. *
  301. * @param mixed $value
  302. * @return scalar
  303. * @access public
  304. */
  305. public function search( $value ) {
  306. if ( !($key = array_search($value, $this->var)) )
  307. return -1;
  308. return $key;
  309. }
  310. /**
  311. * Remove duplicate values from the array.
  312. * Will compare object states.
  313. *
  314. * @param void
  315. * @return void
  316. * @access public
  317. */
  318. public function unique() {
  319. $this->var = array_unique($this->var);
  320. }
  321. public function prefix( $prefix ) {
  322. $this->var = array_prefix_values($prefix, $this->var);
  323. return $this;
  324. }
  325. public function postfix( $postfix ) {
  326. $this->var = array_postfix_values($postfix, $this->var);
  327. return $this;
  328. }
  329. /**
  330. * Clears the contents of the array.
  331. *
  332. * @param void
  333. * @return void
  334. * @access public
  335. */
  336. public function clear() {
  337. $this->var = array();
  338. }
  339. /**
  340. * Check to see if the array is empty
  341. *
  342. * @param void
  343. * @return boolean
  344. * @access public
  345. */
  346. public function isEmpty() {
  347. return empty($this->var);
  348. }
  349. /**
  350. * Return chunks of the same size of this array.
  351. *
  352. * @param integer $size
  353. * @return self
  354. * @access public
  355. */
  356. public function chunk( $size ) {
  357. foreach(array_chunk($this->var, $size, true) as $value) {
  358. $var[] = new $class($value);
  359. }
  360. return static::getClass()->newInstance($var);
  361. }
  362. /**
  363. * Reverse the order of the array.
  364. *
  365. * @param void
  366. * @return ArraDataStructure
  367. * @access public
  368. */
  369. public function reverse() {
  370. $this->var = array_reverse($this->var, true);
  371. return $this;
  372. }
  373. /**
  374. * Sort the data in a case-insensitive natural order.
  375. *
  376. * @param void
  377. * @return void
  378. * @access public
  379. */
  380. public function sort() {
  381. natcasesort($this->var);
  382. }
  383. /**
  384. * Remove the element at the specified key.
  385. *
  386. * @param scalar $key
  387. * @return void
  388. * @access public
  389. */
  390. public function remove( $key ) {
  391. $var = $this->var[$key];
  392. unset($this->var[$key]);
  393. return $var;
  394. }
  395. /**
  396. * Change the case of the keys.
  397. * Accepts CASE_LOWER or CASE_UPPER
  398. *
  399. * @param constant $case
  400. * @return void
  401. * @access public
  402. */
  403. public function keyCase( $case = CASE_LOWER ) {
  404. $this->var = array_change_key_case($this->var, $case);
  405. }
  406. /**
  407. * Merge the Mergable object into this structure.
  408. * This duplicate keys result in data being preserved
  409. * by this object and ignored from the source object.
  410. *
  411. * @param Mergable $object
  412. * @return void
  413. * @access public
  414. */
  415. public function merge( Iterable $var ) {
  416. $var = static::validate($var);
  417. foreach( $var as $key=>$value ) {
  418. if( $this->hasKey($key) &&
  419. $value instanceOf Iterable &&
  420. $this->var[$key] instanceOf Iterable ) {
  421. $this->var[$key]->merge($value);
  422. }
  423. }
  424. $this->var = array_merge($this->var, $var);
  425. return $this;
  426. }
  427. /**
  428. * Return a slice of the array, given an offset and a length.
  429. * If offset is negetive the sequence will start from the end.
  430. * If length is omitted then returns everything from offset on.
  431. * The keys of the returned array are preserved
  432. *
  433. * @param integer $offset
  434. * @param integer $length default NULL
  435. * @return self
  436. * @access public
  437. */
  438. public function slice( $offset, $length = NULL ) {
  439. return static::getClass()->newInstance(array_slice($this->var, $offset, $length, true));
  440. }
  441. /**
  442. * Splice (delete only) a section of the array.
  443. * If offset is negetive the sequence will start from the end.
  444. * If length is omitted then removes everything from offset on.
  445. * Returns the number of deleted elements
  446. *
  447. * @param integer $offset
  448. * @param integer $length
  449. * @param self $replacement
  450. * @return integer
  451. * @access public
  452. */
  453. public function splice( $offset, $length = NULL ) {
  454. return array_splice($this->var, $offset, $length);
  455. }
  456. /**
  457. * Generate an associated array using a fill
  458. * value from start index for a certain length
  459. * of elements
  460. *
  461. * @param integer $start
  462. * @param integer $length
  463. * @param scalar $value
  464. * @access public
  465. */
  466. abstract public function fill( $value );
  467. abstract public function each( Closure $closure );
  468. public static function validate( $array ) {
  469. /* Check parameters */
  470. if( is_array($array) )
  471. $array = $array;
  472. elseif( is_null($array) )
  473. $array = array();
  474. elseif( $array instanceOf Iterable )
  475. $array = $array->__toArray();
  476. else
  477. throw new InvalidTypeException($array, 'Array');
  478. return (array) $array;
  479. }
  480. }
  481. ?>