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