How to "simulate" a Generator in versions prior to PHP 5.5?

3

As of PHP 5.5 we can use yield instead of return in functions and, with that, we create Generators .

The reasons for using yield can be seen here What are the advantages of using a Generator (yield) in PHP?

But I had a question: How could I do something similar to a Generator in versions prior to PHP 5.5?

I would like an example where I could replace the range function, because of the memory economy.

PHP 5.5 Example:

function xrange($start, $limit, $step = 1) {

    for ($i = $start; $i >= $limit; $i += $step) {
        yield $i;
    }
}
    
asked by anonymous 01.09.2015 / 17:42

2 answers

3

What is a generator function?

The generator function is effectively a more compact and efficient way to write an Iterator. It allows you to define a function (your xrange), to calculate and return values while you are looping:

foreach (xrange(1, 10) as $key => $value) {
    echo "$key => $value", PHP_EOL;
}

Output:

0  =>  1 
1  =>  2 
... 
9  =>  10

Since old versions are not supported, can I do it with "normal" functions ??

Now you may wonder why not just use "Old and good native range" to reach this exit. And you are right. The output would be the same. The difference is how we got there .

When we use range , this will execute the entire array of numbers in memory and return the entire array to the foreach which will then supply the values. In other words, foreach will operate in the array itself. The range and foreach will only "chat" once. Think of it as getting a package at the post office. The deliveryman will deliver you the package and leave. And then you unwrap the entire package, taking everything in.

Examples:

<?php
// array(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12)
foreach (range(0, 12) as $number) {
    echo $number;
}

// The step parameter
// array(0, 10, 20, 30, 40, 50, 60, 70, 80, 90, 100)
foreach (range(0, 100, 10) as $number) {
    echo $number;
}

// Usage of character sequences
// array('a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i');
foreach (range('a', 'i') as $letter) {
    echo $letter;
}
// array('c', 'b', 'a');
foreach (range('c', 'a') as $letter) {
    echo $letter;
}
?>
    
01.09.2015 / 20:11
1

To simulate a Generator in versions prior to PHP 5.5 , it would be necessary to create a class that implements Iterator .

Here's how it would look:

class XRange implements Iterator
{
    protected $value = 0;

    protected $limit;

    protected $step;

    protected $initial;

    protected $key = 0;

    public function __construct($value, $limit, $step = 1)
    {
        $this->value = $this->initial = $value;

        $this->limit = $limit;

        $this->step = $step;
    }

    public function rewind()
    {
        $this->value = $this->initial;
    }

    public function current()
    {
        return $this->value;
    }

    public function next()
    {
        $this->value += $this->step;

        ++$this->key;
    }

    public function valid()
    {
        return $this->value <= $this->limit;
    }

    public function key()
    {
        return $this->key;
    }
}

And we can use it simply like this:

foreach(new XRange(1, 10, 1) as $value) {

    echo $value;
}

Result:

  

12345678910

See working at IDEONE

Still thinking of a way to make the code simpler, we could do this:

function xrange($value, $limit, $step = 1)
{
     return new XRange($value, $limit, $step);
}


foreach(xrange(1, 10) as $key => $value) {

}

It is worth remembering that between the implementation of Iterator would be faster than the range function, since in a processing of 1 10.000 , range would be a "villain" in memory consumption; already in the case of class XRange we would have a value for each iteration.

    
01.09.2015 / 23:01