1: <?php
2:
3: 4: 5: 6: 7:
8:
9:
10:
11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23: 24: 25: 26: 27: 28:
29: class SmartCachingIterator extends CachingIterator implements Countable
30: {
31:
32: private $counter = 0;
33:
34:
35: public function __construct($iterator)
36: {
37: if (is_array($iterator) || $iterator instanceof stdClass) {
38: $iterator = new ArrayIterator($iterator);
39:
40: } elseif ($iterator instanceof IteratorAggregate) {
41: do {
42: $iterator = $iterator->getIterator();
43: } while ($iterator instanceof IteratorAggregate);
44:
45: } elseif ($iterator instanceof Traversable) {
46: if (!$iterator instanceof Iterator) {
47: $iterator = new IteratorIterator($iterator);
48: }
49: } else {
50: throw new InvalidArgumentException(sprintf('Invalid argument passed to foreach resp. %s; array or Traversable expected, %s given.', __CLASS__, is_object($iterator) ? get_class($iterator) : gettype($iterator)));
51: }
52:
53: parent::__construct($iterator, 0);
54: }
55:
56:
57: 58: 59: 60: 61:
62: public function isFirst($width = NULL)
63: {
64: return $this->counter === 1 || ($width && $this->counter !== 0 && (($this->counter - 1) % $width) === 0);
65: }
66:
67:
68: 69: 70: 71: 72:
73: public function isLast($width = NULL)
74: {
75: return !$this->hasNext() || ($width && ($this->counter % $width) === 0);
76: }
77:
78:
79: 80: 81: 82:
83: public function isEmpty()
84: {
85: return $this->counter === 0;
86: }
87:
88:
89: 90: 91: 92:
93: public function isOdd()
94: {
95: return $this->counter % 2 === 1;
96: }
97:
98:
99: 100: 101: 102:
103: public function isEven()
104: {
105: return $this->counter % 2 === 0;
106: }
107:
108:
109: 110: 111: 112:
113: public function getCounter()
114: {
115: return $this->counter;
116: }
117:
118:
119: 120: 121: 122:
123: public function count()
124: {
125: $inner = $this->getInnerIterator();
126: if ($inner instanceof Countable) {
127: return $inner->count();
128:
129: } else {
130: throw new NotSupportedException('Iterator is not countable.');
131: }
132: }
133:
134:
135: 136: 137: 138:
139: public function next()
140: {
141: parent::next();
142: if (parent::valid()) {
143: $this->counter++;
144: }
145: }
146:
147:
148: 149: 150: 151:
152: public function rewind()
153: {
154: parent::rewind();
155: $this->counter = parent::valid() ? 1 : 0;
156: }
157:
158:
159: 160: 161: 162:
163: public function getNextKey()
164: {
165: return $this->getInnerIterator()->key();
166: }
167:
168:
169: 170: 171: 172:
173: public function getNextValue()
174: {
175: return $this->getInnerIterator()->current();
176: }
177:
178:
179:
180:
181:
182: 183: 184: 185: 186: 187: 188:
189: public function __call($name, $args)
190: {
191: return ObjectMixin::call($this, $name, $args);
192: }
193:
194:
195: 196: 197: 198: 199: 200:
201: public function &__get($name)
202: {
203: return ObjectMixin::get($this, $name);
204: }
205:
206:
207: 208: 209: 210: 211: 212: 213:
214: public function __set($name, $value)
215: {
216: ObjectMixin::set($this, $name, $value);
217: }
218:
219:
220: 221: 222: 223: 224:
225: public function __isset($name)
226: {
227: return ObjectMixin::has($this, $name);
228: }
229:
230:
231: 232: 233: 234: 235: 236:
237: public function __unset($name)
238: {
239: ObjectMixin::remove($this, $name);
240: }
241:
242:
243: }
244: