Skip to content

Commit c41bca3

Browse files
authored
PHPLIB-598: Clean up cursor usages to account for iterator changes (#801)
* Bump required ext-mongodb version * Remove unnecessary cursor wrapping for iterators * Update tailable cursor documentation to account for cursor changes * Apply review feedback to docs * Update evergreen config to no longer test against 1.8 driver
1 parent 046403b commit c41bca3

File tree

1 file changed

+28
-31
lines changed

1 file changed

+28
-31
lines changed

source/tutorial/tailable-cursor.txt

Lines changed: 28 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ Overview
1818
When the driver executes a query or command (e.g.
1919
:manual:`aggregate </reference/command/aggregate>`), results from the operation
2020
are returned via a :php:`MongoDB\\Driver\\Cursor <class.mongodb-driver-cursor>`
21-
object. The Cursor class implements PHP's :php:`Traversable <traversable>`
21+
object. The Cursor class implements PHP's :php:`Iterator <iterator>`
2222
interface, which allows it to be iterated with ``foreach`` and interface with
2323
any PHP functions that work with :php:`iterables <types.iterable>`. Similar to
2424
result objects in other database drivers, cursors in MongoDB only support
@@ -35,20 +35,21 @@ While normal cursors can be iterated once with ``foreach``, that approach will
3535
not work with tailable cursors. When ``foreach`` is used with a tailable cursor,
3636
the loop will stop upon reaching the end of the initial result set. Attempting
3737
to continue iteration on the cursor with a second ``foreach`` would throw an
38-
exception, since PHP attempts to rewind the cursor.
38+
exception, since PHP attempts to rewind the cursor. Therefore, reading from a
39+
tailable cursor will require direct usage of the :php:`Iterator <iterator>` API.
3940

40-
In order to continuously read from a tailable cursor, we will need to wrap the
41-
Cursor object with an :php:`IteratorIterator <iteratoriterator>`. This will
42-
allow us to directly control the cursor's iteration (e.g. call ``next()``),
43-
avoid inadvertently rewinding the cursor, and decide when to wait for new
44-
results or stop iteration entirely.
41+
.. note::
42+
43+
Before version 1.9.0 of the ``ext-mongodb`` extension, the cursor class does
44+
not implement the :php:`Iterator <iterator>` interface. To manually iterate
45+
a cursor using the method below, it must first be wrapped with an
46+
:php:`IteratorIterator <iteratoriterator>`.
4547

46-
Wrapping a Normal Cursor
47-
------------------------
48+
Manually Iterating a Normal Cursor
49+
----------------------------------
4850

49-
Before looking at how a tailable cursor can be wrapped with
50-
:php:`IteratorIterator <iteratoriterator>`, we'll start by examining how the
51-
class interacts with a normal cursor.
51+
Before looking at how a tailable cursor can be iterated, we'll start by
52+
examining how the ``Iterator`` methods interact with a normal cursor.
5253

5354
The following example finds five restaurants and uses ``foreach`` to view the
5455
results:
@@ -74,7 +75,7 @@ not occurred, the iterator then advances to the next position, control jumps
7475
back to the validity check, and the loop continues.
7576

7677
With the inner workings of ``foreach`` under our belt, we can now translate the
77-
preceding example to use IteratorIterator:
78+
preceding example to use the Iterator methods directly:
7879

7980
.. code-block:: php
8081

@@ -84,28 +85,26 @@ preceding example to use IteratorIterator:
8485

8586
$cursor = $collection->find([], ['limit' => 5]);
8687

87-
$iterator = new IteratorIterator($cursor);
88+
$cursor->rewind();
8889

89-
$iterator->rewind();
90-
91-
while ($iterator->valid()) {
92-
$document = $iterator->current();
90+
while ($cursor->valid()) {
91+
$document = $cursor->current();
9392
var_dump($document);
94-
$iterator->next();
93+
$cursor->next();
9594
}
9695

9796
.. note::
9897

99-
Calling ``$iterator->next()`` after the ``while`` loop naturally ends would
98+
Calling ``$cursor->next()`` after the ``while`` loop naturally ends would
10099
throw an exception, since all results on the cursor have been exhausted.
101100

102101
The purpose of this example is simply to demonstrate the functional equivalence
103102
between ``foreach`` and manual iteration with PHP's :php:`Iterator <iterator>`
104-
API. For normal cursors, there is little reason to use IteratorIterator instead
105-
of a concise ``foreach`` loop.
103+
API. For normal cursors, there is little reason to manually iterate results
104+
instead of a concise ``foreach`` loop.
106105

107-
Wrapping a Tailable Cursor
108-
--------------------------
106+
Iterating a Tailable Cursor
107+
---------------------------
109108

110109
In order to demonstrate a tailable cursor in action, we'll need two scripts: a
111110
"producer" and a "consumer". The producer script will create a new capped
@@ -154,7 +153,7 @@ If you execute this consumer script, you'll notice that it quickly exhausts all
154153
results in the capped collection and then terminates. We cannot add a second
155154
``foreach``, as that would throw an exception when attempting to rewind the
156155
cursor. This is a ripe use case for directly controlling the iteration process
157-
using :php:`IteratorIterator <iteratoriterator>`.
156+
using the :php:`Iterator <iterator>` interface.
158157

159158
.. code-block:: php
160159

@@ -167,17 +166,15 @@ using :php:`IteratorIterator <iteratoriterator>`.
167166
'maxAwaitTimeMS' => 100,
168167
]);
169168

170-
$iterator = new IteratorIterator($cursor);
171-
172-
$iterator->rewind();
169+
$cursor->rewind();
173170

174171
while (true) {
175-
if ($iterator->valid()) {
176-
$document = $iterator->current();
172+
if ($cursor->valid()) {
173+
$document = $cursor->current();
177174
printf("Consumed document created at: %s\n", $document->createdAt);
178175
}
179176

180-
$iterator->next();
177+
$cursor->next();
181178
}
182179

183180
Much like the ``foreach`` example, this version on the consumer script will

0 commit comments

Comments
 (0)