Сохранение в массив (т.е. iterator_to_array())

yield from не сбрасывает ключи. Ключи, возвращенные из объекта Traversable или массива, сохранятся. Таким образом, некоторые значения, могут пересекаться по ключам с другими yield или yield from, что, при записи в массив, повлечет за собой перезапись уже записанных значений.

Общий случай, когда это имеет значение, это когда iterator_to_array() возвращает массив с ключами по умолчанию. В этом случае можно получить печальный результат. iterator_to_array() имеет второй параметр use_keys, который можно установить в FALSE, для генерации собственных ключей и игнорировании ключей, переданных из объекта Generator.

Пример #5 yield from с iterator_to_array()

function from() {
    yield 1; // ключ 0
    yield 2; // ключ 1
    yield 3; // ключ 2
}
function gen() {
    yield 0; // ключ 0
    yield from from(); // ключи 0-2
    yield 4; // ключ 1
}
// Задайте false вторым параметром для получения массива [0, 1, 2, 3, 4]
var_dump(iterator_to_array(gen()));

Результат выполнения данного примера:


array(3) {
[0]=>
int(1)
[1]=>
int(4)
[2]=>
int(3)
}

Пример #6 Основы использования yield from

function count_to_ten() {
    yield 1;
    yield 2;
    yield from [3, 4];
    yield from new ArrayIterator([5, 6]);
    yield from seven_eight();
    yield 9;
    yield 10;
}
function seven_eight() {
    yield 7;
    yield from eight();
}
function eight() {
    yield 8;
}
foreach (count_to_ten() as $num) {
    echo "$num ";
}

Результат выполнения данного примера:


1 2 3 4 5 6 7 8 9 10

Пример #7 yield from и возвращаемые значения

function count_to_ten() {
    yield 1;
    yield 2;
    yield from [3, 4];
    yield from new ArrayIterator([5, 6]);
    yield from seven_eight();
    return yield from nine_ten();
}
function seven_eight() {
    yield 7;
    yield from eight();
}
function eight() {
    yield 8;
}
function nine_ten() {
    yield 9;
    return 10;
}
$gen = count_to_ten();
foreach ($gen as $num) {
    echo "$num ";
}
echo $gen->getReturn();

Результат выполнения данного примера:


1 2 3 4 5 6 7 8 9 10

function my_transform($value) {
    var_dump($value);
    return $value * 2;
}
function my_function(array $values) {
    foreach ($values as $value) {
        yield my_transform($value);
    }
}
$data = [1, 5, 10];
// my_transform() won't be called inside my_function()
my_function($data);
# my_transform() will be called.
foreach (my_function($data) as $val) {
    // ...
}
function gndn()
{
}
foreach(gndn() as $it)
{
    echo 'FNORD';
}
function fibonacci($item) {
    $a = 0;
    $b = 1;
    for ($i = 0; $i < $item; $i++) {
        yield $a;
        $a = $b - $a;
        $b = $a + $b;
    }
}
# give me the first ten fibonacci numbers
$fibo = fibonacci(10);
foreach ($fibo as $value) {
    echo "$value\n";
}
class CachedGenerator {
    protected $cache = [];
    protected $generator = null;
    public function __construct($generator) {
        $this->generator = $generator;
    }
    public function generator() {
        foreach($this->cache as $item) yield $item;
        while( $this->generator->valid() ) {
            $this->cache[] = $current = $this->generator->current();
            $this->generator->next();
            yield $current;
        }
    }
}
class Foobar {
    protected $loader = null;
    protected function loadItems() {
        foreach(range(0,10) as $i) {
            usleep(200000);
            yield $i;
        }
    }
    public function getItems() {
        $this->loader = $this->loader ?: new CachedGenerator($this->loadItems());
        return $this->loader->generator();
    }
}
$f = new Foobar;
# First
print "First\n";
foreach($f->getItems() as $i) {
    print $i . "\n";
    if( $i == 5 ) {
        break;
    }
}
# Second (items 1-5 are cached, 6-10 are loaded)
print "Second\n";
foreach($f->getItems() as $i) {
    print $i . "\n";
}
# Third (all items are cached and returned instantly)
print "Third\n";
foreach($f->getItems() as $i) {
    print $i . "\n";
}
//Example of class implementing IteratorAggregate using generator
class ValueCollection implements IteratorAggregate
{
    private $items = array();
   
    public function addValue($item)
    {
        $this->items[] = $item;
        return $this;
    }
   
    public function getIterator()
    {
        foreach ($this->items as $item) {
            yield $item;
        }
    }
}
//Initializes a collection
$collection = new ValueCollection();
$collection
        ->addValue('A string')
        ->addValue(new stdClass())
        ->addValue(NULL);
foreach ($collection as $item) {
    var_dump($item);
}

 This is little example of using generators with recursion. Used version of php is 5.5.5
define ("DS", DIRECTORY_SEPARATOR);
define ("ZERO_DEPTH", 0);
define ("DEPTHLESS", -1);
define ("OPEN_SUCCESS", True);
define ("END_OF_LIST", False);
define ("CURRENT_DIR", ".");
define ("PARENT_DIR", "..");
function DirTreeTraversal($DirName, $MaxDepth = DEPTHLESS, $CurrDepth = ZERO_DEPTH)
{
  if (($MaxDepth === DEPTHLESS) || ($CurrDepth < $MaxDepth)) {
    $DirHandle = opendir($DirName);
    if ($DirHandle !== OPEN_SUCCESS) {
      try{
        while (($FileName = readdir($DirHandle)) !== END_OF_LIST) { //read all file in directory
          if (($FileName != CURRENT_DIR) && ($FileName != PARENT_DIR)) {
            $FullName = $DirName.$FileName;
            yield $FullName;
            if(is_dir($FullName)) { //include sub files and directories
              $SubTrav = DirTreeTraversal($FullName.DS, $MaxDepth, ($CurrDepth + 1));
              foreach($SubTrav as $SubItem) yield $SubItem;
            }
          }
        }
      } finally {
        closedir($DirHandle);
      }
    }
  }
}
$PathTrav = DirTreeTraversal("C:".DS, 2);
print "<pre>";
foreach($PathTrav as $FileName) printf("%s\n", $FileName);
print "</pre>";</code></pre>

-15
 Note that you can't use count() on generators.
/**
* @return integer[]
*/
function xrange() {
    for ($a = 0; $a < 10; $a++)
    {
        yield $a;
    }
}
function mycount(Traversable $traversable)
{
    $skip = 0;
    foreach($traversable as $skip)
    {
        $skip++;
    }
    return $skip;
}
echo "Count:" . count(xrange()). PHP_EOL;
echo "Count:" . mycount(xrange()). PHP_EOL;

 Another Fibonacci sequence with yield keyword:

function getFibonacci($first, $second, $total) {
  yield $first;
  yield $second;
  for ($i = 1, $total -= 2; $i <= $total; $i++) {
    $sum = $first + $second;
    $first = $second;
    $second = $sum;
    yield $sum;
  }
}
// Generate first 10 numbers of the Fibonacci sequence starting from 0, 1
foreach (getFibonacci(0, 1, 10) as $fibonacci) {
  // 0 1 1 2 3 5 8 13 21 34
  echo $fibonacci . " ";
}



Смотрите также:
Описание на ru2.php.net
Описание на php.ru