Mark Baker
Mark Baker

Reputation: 212452

Generator cannot be in a Closure

I'm creating a class that uses a generator to return values when a particular method is called, something like:

class test {
    protected $generator;

    private function getValueGenerator() {
        yield from [1,1,2,3,5,8,13,21];
    }

    public function __construct() {
        $this->generator = $this->getValueGenerator();
    }

    public function getValue() {
        while($this->generator->valid()) {
            $latitude = $this->generator->current();
            $this->generator->next();
            return $latitude;
        }
        throw new RangeException('End of line');
    }
}

$line = new test();

try {
    for($i = 0; $i < 10; ++$i) {
        echo $line->getValue();
        echo PHP_EOL;
    }
} catch (Exception $e) {
    echo $e->getMessage();
}

Which works perfectly well when the generator is defined as a method within the class itself.... but I want to make this more dynamic, and use a closure as the generator, something like:

class test {
    public function __construct() {
        $this->generator = function() {
            yield from [1,1,2,3,5,8,13,21];
        };
    }
}

Unfortunately, when I try to run this, I get

Fatal error: Uncaught Error: Call to undefined method Closure::valid()

in the call to getValue()

Can anybody explain the actual logic of why I can't call the generator this way? And how I might be able to use a closure rather than a hard-coded generator function?

Upvotes: 3

Views: 1523

Answers (1)

Ciaran McNulty
Ciaran McNulty

Reputation: 18858

In the first example you invoke the method, creating the generator:

$this->generator = $this->getValueGenerator();

In the second you do not invoke it, so it's merely a closure:

$this->generator = function() {
    yield from [1,1,2,3,5,8,13,21];
};

Invoking that closure should create the generator (PHP 7 if you don't want to assign an intermediate variable):

$this->generator = (function() {
    yield from [1,1,2,3,5,8,13,21];
})();

Upvotes: 10

Related Questions