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 . ' ';
}
Snippet 2:
function generateBells(int $num)
{
for ($i = 0; $i < $num; $i++) {
yield '๐';
}
}
$hundredBells = generateBells(100); //544 bytes
foreach ($hundredBells as $bell) {
echo $bell . ' ';
}
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
- Generators Overview: https://www.php.net/manual/en/language.generators.overview.php
Top comments (3)
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!
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! ๐
Good article.