18
18
namespace MongoDB \Model ;
19
19
20
20
use Countable ;
21
- use Generator ;
22
21
use Iterator ;
22
+ use IteratorIterator ;
23
23
use Traversable ;
24
24
use function count ;
25
25
use function current ;
@@ -41,7 +41,7 @@ class CachingIterator implements Countable, Iterator
41
41
/** @var array */
42
42
private $ items = [];
43
43
44
- /** @var Generator */
44
+ /** @var IteratorIterator */
45
45
private $ iterator ;
46
46
47
47
/** @var boolean */
@@ -50,6 +50,9 @@ class CachingIterator implements Countable, Iterator
50
50
/** @var boolean */
51
51
private $ iteratorExhausted = false ;
52
52
53
+ /** @var boolean */
54
+ private $ iteratorPrepared = false ;
55
+
53
56
/**
54
57
* Initialize the iterator and stores the first item in the cache. This
55
58
* effectively rewinds the Traversable and the wrapping Generator, which
@@ -61,8 +64,7 @@ class CachingIterator implements Countable, Iterator
61
64
*/
62
65
public function __construct (Traversable $ traversable )
63
66
{
64
- $ this ->iterator = $ this ->wrapTraversable ($ traversable );
65
- $ this ->storeCurrentItem ();
67
+ $ this ->iterator = new IteratorIterator ($ traversable );
66
68
}
67
69
68
70
/**
@@ -82,6 +84,8 @@ public function count()
82
84
*/
83
85
public function current ()
84
86
{
87
+ $ this ->prepareIterator ();
88
+
85
89
return current ($ this ->items );
86
90
}
87
91
@@ -91,6 +95,8 @@ public function current()
91
95
*/
92
96
public function key ()
93
97
{
98
+ $ this ->prepareIterator ();
99
+
94
100
return key ($ this ->items );
95
101
}
96
102
@@ -100,9 +106,15 @@ public function key()
100
106
*/
101
107
public function next ()
102
108
{
109
+ $ this ->prepareIterator ();
110
+
103
111
if (! $ this ->iteratorExhausted ) {
112
+ $ this ->iteratorAdvanced = true ;
104
113
$ this ->iterator ->next ();
114
+
105
115
$ this ->storeCurrentItem ();
116
+
117
+ $ this ->iteratorExhausted = ! $ this ->iterator ->valid ();
106
118
}
107
119
108
120
next ($ this ->items );
@@ -114,6 +126,8 @@ public function next()
114
126
*/
115
127
public function rewind ()
116
128
{
129
+ $ this ->prepareIterator ();
130
+
117
131
/* If the iterator has advanced, exhaust it now so that future iteration
118
132
* can rely on the cache.
119
133
*/
@@ -138,11 +152,24 @@ public function valid()
138
152
*/
139
153
private function exhaustIterator ()
140
154
{
155
+ $ this ->prepareIterator ();
156
+
141
157
while (! $ this ->iteratorExhausted ) {
142
158
$ this ->next ();
143
159
}
144
160
}
145
161
162
+ private function prepareIterator ()
163
+ {
164
+ if ($ this ->iteratorPrepared ) {
165
+ return ;
166
+ }
167
+
168
+ $ this ->iterator ->rewind ();
169
+ $ this ->iteratorPrepared = true ;
170
+ $ this ->storeCurrentItem ();
171
+ }
172
+
146
173
/**
147
174
* Stores the current item in the cache.
148
175
*/
@@ -156,20 +183,4 @@ private function storeCurrentItem()
156
183
157
184
$ this ->items [$ key ] = $ this ->iterator ->current ();
158
185
}
159
-
160
- /**
161
- * Wraps the Traversable with a Generator.
162
- *
163
- * @param Traversable $traversable
164
- * @return Generator
165
- */
166
- private function wrapTraversable (Traversable $ traversable )
167
- {
168
- foreach ($ traversable as $ key => $ value ) {
169
- yield $ key => $ value ;
170
- $ this ->iteratorAdvanced = true ;
171
- }
172
-
173
- $ this ->iteratorExhausted = true ;
174
- }
175
186
}
0 commit comments