PHP generator Generator understanding

Reprinted and sorted from: Send Fan , The Corner of the Wind and Snow , PHP

Manual Generator (Generator)

  • solvable problem

        Quoted from the official website: Generators provide an easier way to implement simple object iteration, with greatly reduced performance overhead and complexity compared to defining classes that implement the Iterator interface. Generators allow you to write code in a foreach block to iterate over a set of data without creating an array in memory, which would push your memory limit (emphasis added), or take up considerable processing time. Instead, you can write a generator function, just like a normal custom function, and instead of returning only once, the generator can yield as many times as needed in order to generate the values ​​that need to be iterated over.

  • Generate implements the Iterator interface
<?php
//Builder
Generator implements Iterator {
    //return the current value
    public mixed current ( void )
    //return the currently generated key
    public mixed key ( void )
    //Generator continues execution
    public void next ( void )
    //Reset the iterator, if the iteration has already started, an exception will be thrown here.
    public void rewind ( void )
    //Pass a value to the generator, the current yield receives the value, and then proceeds to the next yield
    public mixed send ( mixed $value )
    // throw an exception into the generator
    public void throw ( Exception $exception )
    //Check if the iterator is closed, return FALSE if it has been closed, otherwise return TRUE
    public bool valid ( void )
    // serialize callback
    public void __wakeup ( void )
    //Return the return value of the generator function, PHP version 7+
    public mixed getReturn ( void )
}
?>
  • keyword yield
        At the heart of generator functions is the yield keyword. In its simplest form it looks like a return statement, with the difference that normal return returns a value and terminates the execution of the function, whereas yield returns a value to the code that loops through the generator and just pauses execution of the generator function. A generator cannot return a value: doing so will generate a compile error. However return null is a valid syntax and it will terminate the generator and continue execution.


        yield can only be used in functions, otherwise it will report PHP Fatal error: The "yield" expression can only be used inside a function, any function that uses the yield keyword will return a Generator object. Each time the code executes to the yield statement, the execution will be terminated, and the value of the expression in the yield statement will be returned to the Generator object. When the Generator object continues to be iterated, the code following the yield will continue to be executed until all yield statements are executed or there is a return statement. This The renturn statement can only return null, that is, return;, otherwise a compilation error will occur.

  • Understand the execution process and usable functions from examples

        1 Example one

<?php
function xrang($start, $end, $step=1){
    for($i=$start; $i<=$end; $i += $step) {
        yield $i; //yield keyword defines the breakpoint
    }   
}


//foreach (xrang(1, 10000) as $num) {
//  echo $num."\n";
//}


$rang = xrang(1,2);
var_dump($rang).PHP_EOL; //Output: object(Generator)#1 (0) {}
var_dump($rang instanceof Iterator).PHP_EOL; //输出: bool(true)


$ key = $ rang-> key ();
var_dump("key: ".$key).PHP_EOL; //输出: string(6) "key: 0"
$valid = $rang->valid();
var_dump("valid: ".$valid).PHP_EOL; //输出: string(8) "valid: 1"
$current = $rang->current();
var_dump("current: ".$current).PHP_EOL; //输出: string(10) "current: 1"


$rang->next();


$ key = $ rang-> key ();
var_dump("key: ".$key).PHP_EOL; //输出: string(6) "key: 1"
$valid = $rang->valid();
var_dump("valid: ".$valid).PHP_EOL; //输出: string(8) "valid: 1"
$current = $rang->current();
var_dump("current: ".$current).PHP_EOL; //输出: string(10) "current: 2"


$rang->next();


$ key = $ rang-> key ();
var_dump("key: ".$key).PHP_EOL; //输出: string(5) "key: "
$valid = $rang->valid();
var_dump("valid: ".$valid).PHP_EOL; //输出: string(7) "valid: "


//$rang->rewind(); //Reset, in all the documents I have seen so far, rewind() is only implicitly executed when the Generator is called for the first time. Calling after the generator has started to iterate will throw a Fatal error.
?>
        2 Example two
<?php
function gen(){
    echo "1111\n";
    $ ret = (yield 'yield1');
    var_dump ($ ret);
    echo "2222\n";
    $ ret = (yield 'yield2');
    var_dump ($ ret);
    //return;
}
$gen = gen();
var_dump($gen->current()).PHP_EOL;
$a = $gen->send('ret1');
echo "66666\n";
var_dump($a).PHP_EOL;
echo "77777\n";
var_dump($gen->valid()).PHP_EOL;
$b = $gen->send('ret2');
var_dump($b).PHP_EOL;
var_dump($gen->valid()).PHP_EOL;


//1111
//string(6) "yield1"
//string(4) "ret1"
//2222
//66666
//string(6) "yield2"
//77777
//bool(true)
//string(4) "ret2"
//NULL
//bool(false)
?>
    2.1 The execution process is:

        1. First call gen(), enter the function output 1111, execute to the position where the first yield keyword is located, and interrupt (the value of the yield expression is the defined "yield1" at this time, use current() to get it The value of the current expression is string(6) "yield1")
        2. Call the send() method to pass in the value "ret1" to the generator (the value passed into the generator. This value will be used as the generator's current location The return value of the yield), at this time, the generator starts to iterate from the current yield expression, and the program continues to execute   
        . 3. When encountering var_dump, output the value of the current expression "ret1", and continue to output 2222.
        4. Continue to execute, The program comes to the second yield breakpoint. At this time, the value of the expression is the defined value "yield2", because the send() method is called, which returns the current value of the yield (the current() method value). (Check the official documentation of the send method)
        5. $a gets the return value of the send method, which is "yield2", and continues to execute to output "66666", $a, "77777"
        6. Output whether the current generator is available
        7. Continue to execute, Pass the value "ret2" into the generator, and the generator will continue to iterate. The generator is now in the second yield expression, which accepts "ret2" as the return value and assigns it to the variable $ret, and prints out string(4) "ret2".
        8. After printing, $b == NULL,
            8.1 One may be because there is no breakpoint after the generator and no return value (return value is not allowed, or only return is allowed; return; is used to terminate the execution of the generator), $gen->send() method Nothing is returned at all, resulting in $b == NULL
           8.2 Both may be $gen->send('ret2') after passing in the value, the generator iterates this yield, implicitly calling next() and current(), and because there is no yield breakpoint under next(), current() returns NULL, resulting in the return value of send() NULL              8.3 According to the context, the second possibility is more likely


    2.2 About the send() method
        send() generates A value is passed into the generator and used as the result of the yield expression, and the generator continues to execute. If the generator is not in a yield expression when this method is called, it will run to the first yield expression before passing in a value.

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=324495354&siteId=291194637