Generators

PHP & JS

yield;

yield;

  • change function logic
  • return data from right
  • pause execution
  • can send data into left(php)
  • can throw exception

return;

  • stop execution
  • return data from right

vs

Generator

$gen = function(): Generator { 
    echo 'yield ';
    yield 1;
    echo 'yield ';
    yield 2;
    echo 'yield ';
    yield 3;
};

foreach($gen() as $value) {
    echo 'read ';
}

//yield read yield read yield read

Array

$gen = function(): array { 
    $arr = [];
    echo 'save ';
    $arr[] = 1;
    echo 'save ';
    $arr[] = 2;
    echo 'save ';
    $arr[] = 3;

    returm $arr;
};

foreach($gen() as $value) {
    echo 'read ';
}

//save save save read read read

vs

Pros

  • Faster output
  • Less memory usage
  • Less code
  • Easy to debug
  • Native foreach support

Cons

  • Array access (iterator_to_array()/Array.from())
  • Need to learn different thinking

Usage examples

  • Range generator
  • File streaming
  • Lazy loading

Generator

PHP

JS

Generator implements Iterator {
/** Iterator  */
public mixed current ( void )
public mixed key ( void )
public void next ( void )
public void rewind ( void )
public bool valid ( void )
/** Generator */
public mixed getReturn ( void )
public mixed send ( mixed $value )
public mixed throw ( Throwable $exception )
public void __wakeup ( void )
}
Generator.prototype.next(); 
// IteratorResult => 
// { value: ?, done: bool}
Generator.prototype.return(); 
// IteratorResult => 
// { value: undefined, done: true }
Generator.prototype.throw();

new

PHP

$gen = function(): Generator { 
    yield 1;
    yield 2;
    yield 3;
};

$generator = $gen();
echo $generator->current(); //1
$generator->next();
echo $generator->current(); //2
$generator->next();
echo $generator->current(); //3
$generator->next();
echo $generator->current(); //(null)

JS

var gen = function*() { 
  yield 1;
  yield 2;
  yield 3;
}
var generator = gen();
generator.next()
// {value: 1, done: false}
generator.next()
// {value: 2, done: false}
generator.next()
// {value: 3, done: false}
generator.next()
// {value: undefined, done: true}

PHP

$gen = function(): Generator { 
    yield 1;
    yield 2;
    return 4;
    yield 3;
};

$generator = $gen();
echo $generator->current(); //1
$generator->next();
echo $generator->current(); //2
$generator->next();
echo $generator->current(); //(null)
echo $generator->getReturn(); // 4

JS

var gen = function*() { 
  yield 1;
  yield 2;
  return 4;
  yield 3;
}
var generator = gen();
generator.next()
// {value: 1, done: false}
generator.next()
// {value: 2, done: false}
generator.next()
// {value: 4, done: true}
generator.next()
// {value: undefined, done: true}

PHP

$gen = function(): Generator { 
    yield 1 => 'test';
    yield 2 => 'test';
    yield 3 => 'test';
};

foreach ($gen() as $key => $value) {
    echo $key.' '.$value.PHP_EOL;
}

// 1 test
// 2 test
// 3 test

JS

var gen = function*() { 
  yield {key: 1, value : 'test'};
  yield {key: 2, value : 'test'};
  yield {key: 3, value : 'test'};
}

for (let value of gen() ) { 
    console.log(value); 
}

// {key: 1, value: "test"}
// {key: 2, value: "test"}
// {key: 3, value: "test"}

PHP

class ExampleTest extends TestCase
{
    /**
     * @dataProvider exampleDataProvider
     */
    public function testExample($expected, $value)
    {
        $this->assertEquals($expected, $value);
    }

    public function exampleDataProvider(): \Generator
    {
        yield [1,1];
        yield ['test', 'test'];
        
        $object = new \stdClass;
        yield [$object, $object];

        $fixtures = Fixtures::getFixtures();
        yield [$fixtures , $fixtures];
    }
}
Made with Slides.com