按照php的文檔說明
一個生成器函數看起來像一個普通的函數,不同的是普通函數返回一個值,而一個生成器可以yield生成許多它所需要的值。
當一個生成器被調用的時候,它返回一個可以被遍歷的對象.當你遍歷這個對象的時候(例如通過一個foreach循環),PHP 將會在每次需要值的時候調用生成器函數,並在產生一個值之後保存生成器的狀態,這樣它就可以在需要產生下一個值的時候恢復調用狀態。
一旦不再需要產生更多的值,生成器函數可以簡單退出,而調用生成器的代碼還可以繼續執行,就像一個數組已經被遍歷完了。
一個生成器不可以返回值: 這樣做會產生一個編譯錯誤。然而return空是一個有效的語法並且它將會終止生成器繼續執行。
/**
* 安原來的寫法,我需要一個方法來整理數據。nums()會返回一個數組或者其他可以迭代的數據
* 然後再遍歷這個數組
*/
function nums() {
$array = array();
for ($i = 0; $i < 10000; ++$i) {
$array[]= $i;
}
return $array;
}
foreach (nums() as $v){
var_dump($v);
};
/**
* 但是用了yield之後,我不再需要創建一個變量,來存儲這個數據。
* 而是在內部會為生成的值配對連續的整型索引,就像一個非關聯的數組。
* 這樣會省掉很大的內存開銷
*/
function nums2() {
for ($i = 0; $i < 10000; ++$i) {
yield $i;
}
}
foreach (nums2() as $v){
var_dump($v);
};
$handler=function() { $start = microtime(true); yield; $use_time = (microtime(true) - $start) * 1000; echo "the time is ".(int)$use_time."ms\n"; yield; $use_time = (microtime(true) - $start) * 1000; echo "the time2 is ".(int)$use_time."ms\n"; }; //根據文檔的說明 當一個生成器被調用的時候,它返回一個可以被遍歷的對象.當你遍歷這個對象的時候 //PHP 將會在每次需要值的時候調用生成器函數, //也就是說此時並沒有真的調用$handler中定義的函數。而是返回了一個生成器 $generator = call_user_func_array($handler,array()); if ($generator && $generator instanceof \Generator) { //當對生成器進行迭代的時候,才會真正的調用該$handler中定義的函數 if ($generator->current() === false) { /***do some thing**/ } }
生成器也可以通過引用來使用
/**
* 使用引用來生成值
*/
function &gen_reference() {
$value = 3;
while ($value > 0) {
yield $value;
}
}
/*
* 我們可以在循環中修改$number的值,而生成器是使用的引用值來生成,所以gen_reference()內部的$value值也會跟著變化。
*/
foreach (gen_reference() as &$number) {
echo (--$number).'... ';
}
除了通過引用來改變生成器中的數據之外,我們還可以使用send方法傳遞數據
function printer() {
while (true) {
$string = yield;
echo $string;
}
}
$printer = printer();
$printer->send('Hello world!');
但是上面的例子如果沒有 while(true),那麼無論後面send多少次,該生成器只會執行一次。如此說來,似乎可以用這個來控制本函數調用的最多次數?
除了向裡面傳遞數據之外,還可以throw異常。
function application() {
while (true){
try {
yield;
}catch (Exception $e){
echo $e;
}
}
}
$printer = application();
$printer->throw(new Exception("test"));
生成器的嵌套
/**
* 在php7中 可以通過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;
}
$gen = count_to_ten();
foreach ($gen as $num) {
echo "$num ";
}
echo "the return value is ".$gen->getReturn();