the PHP mysqli_result class implements the Traversable interface for some time now. This gives some interesting possibilities like the following piece of code:
The (let's call it) traversal-fetch-mode of the mysqli_result
can not be influenced. So as it is by default the associative array (column-name as key and it's value as value) like mysqli_result::fetch_assoc()
it stays with that.
So this requires an own Iterator
that does the work. So how does a non-foreach iteration of a Mysqli result traditionally look like? Right, the while()
loop:
while($row = $result->fetch_assoc())
{
...
}
Which reads: while the fetch-method does not return NULL
go on. This is a common form to create iteration.
For iterations of this kind I normally use a FetchingIterator
, it is a concrete iterator that turns the PHP specific Iterator
interface (rewind, valid, current, key, next) into a more simplified one. That simplified one goes: next on rewind, next on next and valid until NULL
- which is pretty much the same as the while
loop and can be used for similar working APIs like deprecated mysql or even arrays (compare array_shift etc.). It's also similar to other implementations of iterators in different programming languages, here specifically Java (compare Iterator Design Pattern
(Source Making Guide on Design Patterns) article).
I did outline it rudimentary back last year in my article Some PHP Iterator Fun (Feb 2012) and a much improved, standard implementation of this can be found as FetchingIterator in Iterator Garden which easily allows to do what you want to do.
Let's see an example application:
class ObjectFetchIterator extends FetchingIterator
{
public function __construct(mysqli_result $result, $class) {
parent::__construct(function() use ($result, $class) {
return $result->fetch_object($class);
});
}
}
The mysqli_result::fetch_object()
method which has been previously within the while(...)
has now been moved into the constructor of a FetchingIterator
for mysqli results. This is a pretty straight forward implementation of it then. Alternatively, it's also possible to override the protected fetchNext()
method but I only note it because it's not needed here.
The usage example then is pretty straight forward:
$db = new mysqli('...');
$result = $db->query('...');
$iterator = new ObjectFetchIterator($result, 'myClass');
/* @var $row myClass */
foreach ($iterator as $row)
{
// $row is a myClass now based on fetched values
}
As this example shows, there is no need to use PDO for that and it sounds like a pretty lazy excuse: Changing the whole database layer only for this little detail? No! The opposite is the case: Using an iterator here in the foreach
allows you to de-couple your code from the concrete database access library to the generic type (as it was possible with arrays earlier too, however arrays are by far not that distinct as object types).
Hope this helps even the answer comes a little late. Just came to my attention this wasn't really answered so far.