In the **php5.5.0** version, a new generator * (generators) * feature was added to simplify the complexity of implementing an Iterator interface * (Iterator) * To create a simple iterator.
With the generator, we can easily iterate through a foreach
series of data without having to build the objects in memory to be iterated in advance, greatly reducing the memory overhead.
When the generator function is called, it returns an iterative object, and when the object is iterated, PHP will call the generator function when it is needed and save the state inside the iterator when the generator uses the new keyword to yield
produce a fresh value. When the iterator does not have a new value to generate, the generator function can exit directly and the external function continues execution.
Note that in a generator function, you cannot use the return
return value of a statement, and return
a compiler error occurs when you use the return value. However, return
it is possible to use NULL, which causes the iterator to terminate.
The generator function is the same as the normal function, and the only difference is that the keyword is used within the function yield
. The yield
statement can be said to be the core of the generator function, simply, yield
just like the return
statement, the difference is that the return
function ends after the statement returns, and the use yield
of return, just pause the execution of the function, go to the external function to continue execution, the next time you call the generator function , continue executing the code inside the generator function.
A simple example-the range function of the generator version
A simple example is the use foreach
of the return value of an iterative function range
, which, if invoked range(0, 1000000)
, consumes more than 100M of memory. Using the generator, you may only need to consume 1KB of memory.
<?phpfunction xrange($start, $end) { if ($start > $end) { throw new RuntimeException("起始值不能大于截止值"); } for ($i = $start; $i <= $end; $i += 1) { // 使用yield关键字,每次到这里函数都会返回$i的值,并且控制权交给外部函数继续执行 yield $i; }}foreach (xrange(1, 9) as $number) { echo "$number ";}
The above example output is as follows:
In the example above, we have created a xrange
function called, which uses the yield
constant generation of return values, and the call xrange(1, 9)
creates a generator object. We can modify foreach
this line to print out the xrange
object to see
...$xrange_res = xrange(1, 9);var_dump($xrange_res);foreach( $xrange_res as $number){...
Output
As you can see, it xrange(1, 9)
is true that an object was returned when executed Generator
.
Use the Send method of the Generator object
In the example above, we used the yield
statement as a separate line of statements, that is, the yield
statement produces the result to the outside, then there is no way in the iterative process from the outside of the generator function to get the value?
There is always a way to do this, because the call to the generator function returns an Generator
object, so we can send
pass a value to the generator function externally by calling the method of the object, and after the method is called send
, the yield
send
value sent by the function is received.
<?phpfunction gen() { $ret = (yield ‘yield1‘); var_dump("-->" . $ret); $ret = (yield ‘yield2‘); var_dump("-->" . $ret);}$gen = gen();var_dump($gen->current());var_dump($gen->send(‘ret1‘));var_dump($gen->send(‘ret2‘));
Output:
Here we first create a gen
generator object named, and then we print the $gen->current()
return value of the method, which is the current value produced by the first iteration of the iterator, so it is output yield1
.
Then we call the method, and the $gen->send(‘ret‘)
first statement inside the generator yield
returns the value passed by the method ret1
, so the output $ret
value is ret1
.
The $ret = (yield ‘yield2‘)
second output of the external is then due to the third statement being executed inside the generator var_dump
yield2
. The last call $gen->send(‘ret2‘)
is similar to the first, but this time the generator is not inside the call and yield
yield
is returned NULL
.
Note that in the statement here, the $ret = (yield ‘yield2‘)
parentheses are used to include the yield ‘yield2‘
statement, which is required, and if used in the context of an expression, it must be enclosed yield
yield
in parentheses, otherwise an error will be made.
Returns an associative array
In the previous example, we used the yield
keyword to return always a single value, in fact PHP also provides support for returning an associative array, the basic syntax:
yield key => val
Use this syntax format to return the same results as the traversal management array when foreach is used.
<?phpfunction gen2() { $array = [ ‘username‘ => ‘mylxsw‘, ‘site‘ => ‘http://aicode.cc‘ ]; foreach ($array as $key => $val) { yield $key => $val; }}foreach(gen2() as $key => $val) { var_dump($key . ‘ : ‘ . $val);}
Output:
Using references
We can also have the generator return data as a reference, so that the values of the generator's internal data can be modified directly outside the generator.
<?phpfunction &gen_reference() { $value = 3; while ($value > 0) { yield $value; }}foreach (gen_reference() as &$number) { echo (--$number).‘... ‘;}
In the above example, it is important to note that the definition and traversal of the generator function is used &$number
.
Finally, the generator is not exactly the same as the custom iterator object, and once the generator starts iterating, it can no longer be rewind
iterated until the iteration is complete. If you want to iterate over a generator object multiple times, you can call the generator function multiple times to create a new generator object or use the Clone keyword.
Reference:
- Cooperative multitasking using coroutines (in php!)
- Generators
Php5.5 new Features generators detailed