DEV Community

Anders Bjรถrkland
Anders Bjรถrkland

Posted on

Yielding Bells ๐Ÿ”” - generators in PHP

Today we want us some bells in our Christmas, so let's create them. PHP has a neat feature called generators. Generators are functions that can be used to create iterators, and they don't need a large overhead to create them. For performance sake, let's compare two code snippets.

Snippet 1:

<?php 

function produceBells(int $num)
{
    $bells = [];
    for ($i = 0; $i < $num; $i++) {
        $bells[] = '๐Ÿ””';
    }
    return $bells;
}
$hundredBells = produceBells(100); // 8.3KB

foreach ($hundredBells as $bell) {
    echo $bell . ' ';
}
Enter fullscreen mode Exit fullscreen mode

Snippet 2:

function generateBells(int $num)
{
    for ($i = 0; $i < $num; $i++) {
        yield '๐Ÿ””';
    }
}
$hundredBells = generateBells(100); //544 bytes

foreach ($hundredBells as $bell) {
    echo $bell . ' ';
}
Enter fullscreen mode Exit fullscreen mode

Both these snippets will produce this output:

๐Ÿ”” ๐Ÿ”” ๐Ÿ”” ๐Ÿ”” ๐Ÿ”” ๐Ÿ”” ๐Ÿ”” ๐Ÿ”” ๐Ÿ”” ๐Ÿ”” ๐Ÿ”” ๐Ÿ”” ๐Ÿ”” ๐Ÿ”” ๐Ÿ”” ๐Ÿ”” ๐Ÿ”” ๐Ÿ”” ๐Ÿ”” ๐Ÿ”” ๐Ÿ”” ๐Ÿ”” ๐Ÿ”” ๐Ÿ”” ๐Ÿ”” ๐Ÿ”” ๐Ÿ”” ๐Ÿ”” ๐Ÿ”” ๐Ÿ”” ๐Ÿ”” ๐Ÿ”” ๐Ÿ”” ๐Ÿ”” ๐Ÿ”” ๐Ÿ”” ๐Ÿ”” ๐Ÿ”” ๐Ÿ”” ๐Ÿ”” ๐Ÿ”” ๐Ÿ”” ๐Ÿ”” ๐Ÿ”” ๐Ÿ”” ๐Ÿ”” ๐Ÿ”” ๐Ÿ”” ๐Ÿ”” ๐Ÿ”” ๐Ÿ”” ๐Ÿ”” ๐Ÿ”” ๐Ÿ”” ๐Ÿ”” ๐Ÿ”” ๐Ÿ”” ๐Ÿ”” ๐Ÿ”” ๐Ÿ”” ๐Ÿ”” ๐Ÿ”” ๐Ÿ”” ๐Ÿ”” ๐Ÿ”” ๐Ÿ”” ๐Ÿ”” ๐Ÿ”” ๐Ÿ”” ๐Ÿ”” ๐Ÿ”” ๐Ÿ”” ๐Ÿ”” ๐Ÿ”” ๐Ÿ”” ๐Ÿ”” ๐Ÿ”” ๐Ÿ”” ๐Ÿ”” ๐Ÿ”” ๐Ÿ”” ๐Ÿ”” ๐Ÿ”” ๐Ÿ”” ๐Ÿ”” ๐Ÿ”” ๐Ÿ”” ๐Ÿ”” ๐Ÿ”” ๐Ÿ”” ๐Ÿ”” ๐Ÿ”” ๐Ÿ”” ๐Ÿ”” ๐Ÿ”” ๐Ÿ”” ๐Ÿ”” ๐Ÿ”” ๐Ÿ””

Is that a hundred bells? I sure hope so, I get lost when counting them!

The question is now, which is less memory intensive, and why is Snippet 2?! I ran both snippets with profile-mode on Xdebug and found the following result:

Snippet Type Memory usage
1 Array 8280 bytes
2 Generator 544 bytes

As we can see, the generator is a lot more memory efficient than the array. The reason for this is that generators are lazy, and only generate the values when they are needed. This means that the memory usage is only as high as the amount of values that are actually needed. And as we loop through one item at a time to echo it out, that is as much memory as will be used. You could output a million of these things if you like, and the memory usage would not be that much higher. (In fact, it remained at 544 bytes when I ran it.)

So what's the cost? Generators, while memory efficient, are not as time efficient. My machine is not stable enough (poor potato), to do a fair benchmarking. But at a thousand bells we got 9.2 ms for the array and 11.6 ms for the generator. So is it worth it for you to use generators? That question has not only to do with time versus memory cost. If you don't know how often you will need to access an array (or iterator) value, you may need to use a generator anyway.

What about you?

Have you ever tried a generator before? What use cases do you have or think you would have for generators? Comment below and let us know what you think โœ

Further Reading

Discussion (3)

Collapse
dawiddahl profile image
Dawid Dahl

Really like generators! The concept really clicked when I first heard them described as "pausable functions". Also, that you can get information in and out at any times is really cool, like opening a portal between different dimensions. ๐ŸŒŒ

When I used Redux Saga for frontend state management for a project I got to go more in depth with them, really fun!

Collapse
andersbjorkland profile image
Anders Bjรถrkland Author

Plausible functions are a great way to put it! ๐Ÿ’ก

I was completely taken off guard the first time I saw yield in a code base. I just thought of them as alternative to returning arrays until I learned about what generators are.

I haven't used them a lot but now I know what I'm looking at in third party code! ๐Ÿ˜…

Collapse
epsi profile image
E.R. Nurwijayadi

Good article.