9

Yesterday, I've learned that PHP has a yield() method. I was unure about its usefulness in PHP.

A colleague said it could help for SQL statements returning many rows causing potential memory issues. I believe he was refering to fetchAll(). But, instead of using fetchAll(), one can also use fetch() and process rows one-by-one. So, yield() is not key to solving the issue he is referring to.

Am I missing something about yield() vs fetch() here? Are there more benefits to using yield() and generators?

P.S.: It's true that it's easier to write clean, readable and maitainable code in large applications with yield() than with with fetch().

Your Common Sense
  • 156,878
  • 40
  • 214
  • 345
Jérôme Verstrynge
  • 57,710
  • 92
  • 283
  • 453
  • 3
    Well, PDO is not a very good example for yield usefilness, because PDO statement already imnplements a traversable interface and can be iterated over using foreach. But with mysqli you can use yield to make mysqli result iterated with foreach. – Your Common Sense Jun 15 '16 at 07:36
  • 1
    Well, in general this comes down to what *generators* are useful for (cause `yield` is an implementation detail of generators). And generators are useful for creating something which behaves like an array (or rather an *iterable*), yet does not store all its data in memory but *generates* it with each iteration as needed. Yes, this can be used in the context of fetching database results, but could also be used to implement an infinite counter or any number of other things. – deceze Jun 15 '16 at 07:58

1 Answers1

15

So, yield() is not key to solving the issue he is referring to.

Exactly.

But it can let you to disguise while()/fetch() sequence as a foreach() call if you prefer to, without memory overhead as well.

However, PDO is not a very good example, because PDOStatement already implements a traversable interface and thus can be iterated over using foreach():

$stmt = $pdo->query('SELECT name FROM users');
foreach ($stmt as $row)
{
    var_export($row);
}

So let's take mysqli for the example API that can only stream results one by one.
Edit. Actually, since 5.4.0 mysqli supports Traversable as well, so there is no point in using yield with mysqli_result either. But meh, let's keep it for the demonstration purpose.

Let's create a generator like this

function mysqli_gen (mysqli_result $res)
{
    while($row = mysqli_fetch_assoc($res))
    {
        yield $row;
    }
}

and now you can get rows using foreach without an overhead:

$res = $mysqli->query("SELECT * FROM users");
foreach (mysqli_gen($res) as $row)
{
    var_export($row);
}
Your Common Sense
  • 156,878
  • 40
  • 214
  • 345