PDO, Iterators and a bit of confusion

Having seen the news that PHP 5.5 is in alpha release I went to see what was new and saw a term I was unfamiliar with - "generators", and ended up reading this RFC. I could immediately see the potential for reducing memory and looping (assuming that the binding of functions and use of yield does not introduce more over head than using a full dataset or looping twice*)....so I started to look at the Iterator examples the RFC gives as a current alternative...and this is where I started to get confused with what to do and what is actually going on.

The example is with respect to reading files from the filesystem. A handler is opened by the Iterator class and, as I understand it, only returns the current line in question.

This got me thinking about how my app works with my database, and the database abstraction layer.

My "getMany()" method in my models executes the fetchAll method of a PDOStatement object, thus returning the entire dataset as a 2D array, which is then often worked with again (eg in some views I loop over the array to create html tables and lists)

So, I'm wondering if there's a way (in PHP < 5.5, ie without generators) to use the Iterator patterns to only have to loop over the data once - or at the very least not have put the entire database into memory (eg just use fetch, working on one row at a time)

Now, the manual says that PDOStatement implements traversable.....but I've yet to find the complete way through.....

any ideas or pointers?

*when I say looping twice I do not mean nested looping, but looping over an array-like structure once to get some other array-like object, then looping over the original or new array later on the the script execution

I said I didn't like ORM!!! <?php $this->model->update($this->request->resources[0])->set($this->request->getData())->getData('count'); ?>

If it implements Traversable, then it's an iterator. You can use it just like you'd use any other iterator. In fact, there's a whole set of functions that work only on Iterators. You'd probably love iterator_apply.

I'm not sure what you expect from iterators in the context of queries, because query objects already are external iterators by means of their "fetch" method -- you just cannot rewind them (which is a general database issue and will apply any iterator wrapping the query stuff).

The only advantage of an explicit iterator is that you can use a foreach loop instead of

PHP Code:

while ($row = $stmt->fetch()) ...

If this is really that important to you, just replace DB::returnArray() with a method which returns the actual PDO statement. The getMany() method will then return the specific statement and allow the caller to iterate over the result set.

You don't need to define your own iterator class, because PDOStatement already has everything you need.

You already have an iterator. You could just return it and use it one level higher than you're using it now. Instead of calling FetchAll on it (or whatever), just return it and then have your code above this foreach over it.

Of course, that stops abstraction from being...abstracted. You could also make a resultset object which itself implements either ArrayAccess/ArrayIterator or Traversable and then wrap the PDO result in THAT so that you have a custom wrapper library.

Using the PDO iterator directly goes against the concept of database abstraction. The reason you're using fetchAll is because you don't want your code outside your database library to have to deal with database-specific code (though PDO is, itself, an abstraction library).

To try to simplify this post:
Your getMany() function right now returns an array. You can either:
1) Have it return the iterator, use it in someObject

2) Wrap the iterator in another iterator of your own design, use THAT in someObject

3) Move on from this problem because very few people do it this way anyway, use iterators for something not so central and complicated.

To try to simplify this post:
Your getMany() function right now returns an array. You can either:
1) Have it return the iterator, use it in someObject

2) Wrap the iterator in another iterator of your own design, use THAT in someObject

3) Move on from this problem because very few people do it this way anyway, use iterators for something not so central and complicated.

Okay, I hear you.

Really, I'm looking for performance increases - which, I admit, I could find bigger savings elsewhere in my app but this whole iterators/generators is new to me and got me interested...and confused, but the confusion is clearing

I said I didn't like ORM!!! <?php $this->model->update($this->request->resources[0])->set($this->request->getData())->getData('count'); ?>

Also worth mentioning: IteratorAggregate. Lets you define a method that returns an iterator to use, so if your class wraps an array and you want to iterate over that, return an ArrayIterator($this->wrapped_array) - don't have to implement all the Iterator methods.