Jens Segers on Mar 14 2015

Behold the power of yield

The first time I read about yield in PHP was in the PHP 5.5 changelog back in 2013. Actually, I did not really give it that much attention, since I thought it was not that big of deal at the time. It wasn't until I was using it in Python to process large amounts of data, that I started using it in PHP as well.

So what is this sorcery called yield? The yield keyword is used by generators, which provide a simple way to implement iterators without having to create a class that implements the Iterator interface. A generator allows you to write code that iterates over a set of data without needing to build an array in memory that is returned at the end.

Imagine we're calculating perceptual hashes for a set of images, so that we can compare them against a given image. You could write a function like this:

function calculateHashes(array $images, ImageHash $hasher) {
    $results = [];

    foreach ($images as $key => $image) {
        $results[$key] = $hasher->hash($image->path);
    }

    return $results;
}

If we call the code above, it will start calculating the hashes and append them to the $results array. As you can see, the caller of this function will have to wait for all the images to be processed before it can start doing stuff with the results. Even if the first image would be a perfect match.

Using a generator, the function would look like this:

function calculateHashes(array $images, ImageHash $hasher) {
    foreach ($images as $key => $image) {
        yield $key => $hasher->hash($image->path);
    }
}

It's a bit difficult to explain what the yield statement does, but here I go; It behaves similar to the return statement, but rather than returning only the current value, it returns an object that implements the Iterator interface. When you iterate over that object, PHP will call the generator function each time it needs a value, and save the current state of the generator until the next value is required.

Because it immediately returns the value to the caller for every loop, instead of appending it to an array, it uses less memory. And if the caller decides to stop iterating because it has found what it needs, it will also speed up your code!

I have not seen yield being used by many other developers, nor have I seen it in many PHP projects yet. But I hope developers will catch up and see how it can improve memory usage and speed like I did.


Comments

jenssegers 2 years ago

@Verron for data processing this can definitely improve performance. For small applications maybe not that much.


Verron 2 years ago

Been meaning to give this a try. A co-worker told me about it back in January. Have you seen any performance improvement?


wouterds 2 years ago

Cool