Finally generators exist as of PHP 5.5

PHP 5.5 has recently been released as an ALPHA release, meaning there are still bugs, code is being tested and features being added. With the 5.5 release, many of us PHP developers have a few wonderful new features that we should be taking advantage of almost immediately.

Firstly, there is the finally statement available within our try-catch blocks. For those of readers who are not sure what the finally block is, it allows for any code to be placed within to always be executed after the try and catch blocks, regardless of whether an exception has been thrown, and before normal execution continues.

A simple example:

try
{
    throw new \Exception('This is an example.');
}
catch( \Exception $exception )
{
    // Handle the exception
}
finally
{
    print 'Hello World!'
}

It is important to note that the above code snippet will always print the Hello World, regardless of whether or not an exception has been thrown. It is not uncommon to see finally statements being used for freeing resources, returning desired values from functions or class methods and so on.

Another new language feature in PHP 5.5 is generators. Generators allow for an overly easy implementation of simple, forward-only, iterators without the complexity of implementing a concrete class that implements the Iterator interface.

A generator allows for basic loop constructs to be written and used for iteration over a set of data without the need to build large datasets in memory (which typically causes the memory limit to be exceeded) and has a fraction of the processing time to generate. Generator functions are very similar in their definition to regular functions, the difference is that a generator cannot have any return statements that returns a value and they make use of a new keyword, yield. A generator may yield values as many times as it requires in order to provide the values required to be iterated over.

Using the example (found on PHP.net), a simple function that is reimplementing the functionality of range() to generate an array of values would use an excessive amount of memory. If the range was from zero to one million (0, 1000000), the result would be well over 100 MB of memory usage. Alternatively, implementing xrange (a custom range function using generators) would only create enough memory to create the Iterator instance and track its current states.

A simple example:

<?php

function xrange($min, $max, $step = 1)
{
    if( $min < $max )
    {
        if( $step <= 0 )
        {
            throw new InvalidArgumentException(sprintf('The specified step "%s" cannot be less than or equal to zero.'));
        }

        for( $i = $min; $i <= $max; $i += $step )
        {
            yield $i;
        }
    }
    else
    {
        if( $step >= 0 )
        {
            throw new InvalidArgumentException(sprintf('The specified step "%s" cannot be greater than or equal to zero.'));
        }

        for( $i = $min; $i >= $max; $i += $step )
        {
            yield $i;
        }
    }
}

/* The output will be: 1 2 3 4 5 6 7 8 9 10 */
foreach( xrange(1, 10) as $number )
{
    print $number . ' ';
}

However, there are many more elegant and practical uses to generators. For example, imagine the need to process a relatively large data file, instead of reading in line by line, creating an dataset of the read data and then performing operations, it is possible to instead use generators and only process the required data separately via a processing routine.

Over the coming weeks and months, I am sure there will be more posts and thoughts on the uses of generators, so keep an eye open for them!

Happy Generating!