PHP learning notes 17: iterators and generators

PHP learning notes 17: iterators and generators

Source: php.net

Iterator related concepts widely exist in various programming languages and design patterns. Here are two related articles I recommend:

iterator

In php, you can implement Iterator interface To implement an iterator:

<?php
class MyClass implements Iterator
{
    public function current(): mixed
    {
    }
    public function next(): void
    {
    }
    public function rewind(): void
    {
    }
    public function key(): mixed
    {
    }
    public function valid(): bool
    {
    }
}

The functions of these methods are:

  • Current, returns the current element corresponding to the cursor.
  • Next, move the cursor to the next element.
  • rewind to reset the cursor to the start position.
  • key to return the cursor position.
  • Valid, whether the current position of the cursor is valid (used to judge whether to end the traversal).

php's iterator interface is more complex than Python's, but the advantage is that it includes the rewind method, which can reset the iterator to repeat the iteration.

The following is an example of a program that can segment words in a string:

<?php
class Sentence implements Iterator
{
    private array $words;
    private int $index = 0;
    public function __construct(string $string)
    {
        $this->words = str_word_count($string, 1);
    }
    public function current(): mixed
    {
        return $this->words[$this->index];
    }
    public function rewind(): void
    {
        $this->index = 0;
    }
    public function next(): void
    {
        $this->index++;
    }
    public function key(): mixed
    {
        return $this->index;
    }
    public function valid(): bool
    {
        return isset($this->words[$this->index]);
    }
}
$sentence = new Sentence("hello world, how are you!");
foreach ($sentence as $word) {
    echo $word . PHP_EOL;
}
echo PHP_EOL;
// hello
// world
// how
// are
// you

php has preset some common iterators. Please refer to the official manual for details iterator .

generator

The generator can be regarded as a special iterator. You can use the generator function to easily create a generator:

<?php
function sentence(string $str)
{
    $words = str_word_count($str, 1);
    foreach ($words as $key => $val) {
        yield $val;
    }
}
foreach (sentence("hello world, how are you!") as $word) {
    echo $word . PHP_EOL;
}
// hello
// world
// how
// are
// you

The advantage of the generator is that it has less implementation code than the iterator, and it can also delegate the call to another generator with the yield from statement to implement a similar multi-level application of the generator. This is quite common when Python's async package implements concurrency.

Here, sentence uses a generator that decomposes a string into letters for traversal:

<?php
function char(string $str): Generator
{
    $len = strlen($str);
    if ($len == 0) {
        yield "";
        return;
    }
    $index = 0;
    do {
        yield substr($str, $index, 1);
        $index++;
    } while ($index <= $len - 1);
}
function sentence(string $str): Generator
{
    $words = str_word_count($str, 1);
    foreach ($words as $key => $val) {
        yield from char($val);
    }
}
foreach (sentence("hello world, how are you!") as $word) {
    echo $word . " ";
}
echo PHP_EOL;
// h e l l o w o r l d h o w a r e y o u 

By using the generator, we can avoid excessive memory consumption caused by traversing large arrays in the program:

<?php
function xrange(int $start, int $end, int $step): Generator
{
    if ($step <= 0) {
        throw new Exception("invlid step param.");
    }
    if ($start < $end) {
        for ($i = $start; $i <= $end; $i += $step) {
            yield $i;
        }
    } else {
        for ($i = $start; $i >= $end; $i -= $step) {
            yield $i;
        }
    }
}
function print_generator(Generator $gen)
{
    foreach ($gen as $val) {
        echo $val . " ";
    }
    echo PHP_EOL;
}
$gen1 = xrange(1, 10, 1);
$gen2 = xrange(20, 3, 3);
print_generator($gen1);
print_generator($gen2);
// 1 2 3 4 5 6 7 8 9 10 
// 20 17 14 11 8 5 

Compared with the built-in range function, the xrange function here can be used to generate super long sequences, and will only occupy a small memory.

It should be noted that the generator function itself returns a generator, which essentially acts as a generator factory method. The data produced by yield is only the iteration result returned each time the generator traverses, not the return value of the generator function. This is easily confused by novices.

The Generator is an instance of the built-in type Generator, so for clarity, you can label the return value of the Generator function as the Generator type.

Because the relevant contents of the generator are summarized in detail in the process of learning Python, here is only a brief introduction to the usage of the generator and iterator in php. You can read more about the generator Python learning note 16: generator.

Thank you for reading.

Previous contents

Keywords: PHP

Added by cdoyle on Fri, 10 Dec 2021 12:40:10 +0200