Deal with Memory Gently using “Yield” in PHP

Did you ever wonder “What is the benefit of having yield in PHP”, I will save you sometime googling; I have a list of points I want to introduce it to you in order to cover yield:

  1. What is yield.
  2. Different between yield & return.
  3. What are yield options.
  4. Conclusion.
  5. References.

1. What is “yield”

A generator function looks just like a normal function, except that instead of returning a value, a generator yields as many values as it needs to.

Look at the following example:

function getValues() {
yield 'value';
}
// print the string "value"
echo getValues();

Of course, this is not how it’s working, the preceding example will give you a fatal error: Object of class Generator could not be converted to string, let us make it clear:

2. Different between “yield” & “return”

The preceding error means that getValues() function doesn’t return a string as expected, let us check its type:

function getValues() {
return 'value';
}
var_dump(getValues()); // string(5) "value"
function getValues() {
yield 'value';
}
var_dump(getValues()); // class Generator#1 (0) {}

Generator class is implementing Iterator interface, which means that you have to loop over the getValue() function in order to get the values:

foreach (getValues() as $value) {
echo $value;
}
// using variable is also alright
$values = getValues();
foreach ($values as $value) {
echo $value;
}

But this is not the only difference!

A generator allows you to write code that uses foreach to iterate over a set of data without needing to build an array in memory, which may cause you to exceed a memory limit.

In the following example we will build an array of 800,000 elements and return it from the function getValues(), and in the meanwhile, we will get the memory allocated to this script by using the function memory_get_usage(), we will get the memory usage every 200,000 elements added, which means that we will put four check points:

What happened in the preceding example is a memory consuming and the output of this script:

0.34 MB
8.35 MB
16.35 MB
32.35 MB

It means that our few lines script consumed over 30 Megabytes of memory, every time you add an element to the array $valuesArray, you increase the size of it in memory.

Let us use the same example with yield:

The output of this script is surprising:

0.34 MB
0.34 MB
0.34 MB
0.34 MB

It doesn’t mean that you migrate from return expressions to yield, but if you are building huge arrays in your application which cause memory issues on the server, so yield suits your case.


3. What are “yield” options

There are many options for yield, I am going to highlight couple of them:

a. Using yield, you can also use return:

function getValues() {
yield 'value';
return 'returnValue';
}
$values = getValues();
foreach ($values as $value) {}
echo $values->getReturn(); // 'returnValue'

b. Returning keys-values:

function getValues() {
yield 'key' => 'value';
}
$values = getValues();
foreach ($values as $key => $value) {
echo $key . ' => ' . $value;
}

Check more here.

4. Conclusion

The main reason of this topic is to clarify the difference between yield and return specially in terms of memory, showing some examples because I found it really important for any developer to consider.

5. References

  1. http://php.net/manual/en/language.generators.syntax.php
  2. http://php.net/manual/en/class.generator.php
  3. http://php.net/manual/en/language.generators.php
  4. http://php.net/manual/en/function.memory-get-usage.php
Like what you read? Give Mustafa Magdi a round of applause.

From a quick cheer to a standing ovation, clap to show how much you enjoyed this story.