Heim > php教程 > php手册 > php生成器的使用 - coder5

php生成器的使用 - coder5

WBOY
Freigeben: 2016-05-20 11:40:45
Original
1382 Leute haben es durchsucht

按照php的文档说明

一个生成器函数看起来像一个普通的函数,不同的是普通函数返回一个值,而一个生成器可以yield生成许多它所需要的值。
当一个生成器被调用的时候,它返回一个可以被遍历的对象.当你遍历这个对象的时候(例如通过一个foreach循环),PHP 将会在每次需要值的时候调用生成器函数,并在产生一个值之后保存生成器的状态,这样它就可以在需要产生下一个值的时候恢复调用状态。
一旦不再需要产生更多的值,生成器函数可以简单退出,而调用生成器的代码还可以继续执行,就像一个数组已经被遍历完了。

一个生成器不可以返回值: 这样做会产生一个编译错误。然而return空是一个有效的语法并且它将会终止生成器继续执行。

<span style="color: #008000;">/*</span><span style="color: #008000;">*
 * 安原来的写法,我需要一个方法来整理数据。nums()会返回一个数组或者其他可以迭代的数据
 * 然后再遍历这个数组
 </span><span style="color: #008000;">*/</span>
<span style="color: #0000ff;">function</span><span style="color: #000000;"> nums() {
    </span><span style="color: #800080;">$array</span> = <span style="color: #0000ff;">array</span><span style="color: #000000;">();
    </span><span style="color: #0000ff;">for</span> (<span style="color: #800080;">$i</span> = 0; <span style="color: #800080;">$i</span> $i<span style="color: #000000;">) {
        </span><span style="color: #800080;">$array</span>[]= <span style="color: #800080;">$i</span><span style="color: #000000;">;
    }
    </span><span style="color: #0000ff;">return</span> <span style="color: #800080;">$array</span><span style="color: #000000;">;
}

</span><span style="color: #0000ff;">foreach</span> (nums() <span style="color: #0000ff;">as</span> <span style="color: #800080;">$v</span><span style="color: #000000;">){
    </span><span style="color: #008080;">var_dump</span>(<span style="color: #800080;">$v</span><span style="color: #000000;">);
};


</span><span style="color: #008000;">/*</span><span style="color: #008000;">*
 * 但是用了yield之后,我不再需要创建一个变量,来存储这个数据。
 * 而是在内部会为生成的值配对连续的整型索引,就像一个非关联的数组。 
 * 这样会省掉很大的内存开销
 </span><span style="color: #008000;">*/</span>
<span style="color: #0000ff;">function</span><span style="color: #000000;"> nums2() {
    </span><span style="color: #0000ff;">for</span> (<span style="color: #800080;">$i</span> = 0; <span style="color: #800080;">$i</span> $i<span style="color: #000000;">) {
        yield </span><span style="color: #800080;">$i</span><span style="color: #000000;">;
    }
}

</span><span style="color: #0000ff;">foreach</span> (nums2() <span style="color: #0000ff;">as</span> <span style="color: #800080;">$v</span><span style="color: #000000;">){
    </span><span style="color: #008080;">var_dump</span>(<span style="color: #800080;">$v</span><span style="color: #000000;">);
};</span>
Nach dem Login kopieren

如果需要在生成器中指定下标 可以 yield $id => $fields;

<span style="color: #800080;">$handler</span>=<span style="color: #0000ff;">function</span><span style="color: #000000;">() {
        </span><span style="color: #800080;">$start</span> = <span style="color: #008080;">microtime</span>(<span style="color: #0000ff;">true</span><span style="color: #000000;">);

        yield;

        </span><span style="color: #800080;">$use_time</span> = (<span style="color: #008080;">microtime</span>(<span style="color: #0000ff;">true</span>) - <span style="color: #800080;">$start</span>) * 1000<span style="color: #000000;">;
        </span><span style="color: #0000ff;">echo</span> "the time is ".(int)<span style="color: #800080;">$use_time</span>."ms\n"<span style="color: #000000;">;
        
        yield;
        </span><span style="color: #800080;">$use_time</span> = (<span style="color: #008080;">microtime</span>(<span style="color: #0000ff;">true</span>) - <span style="color: #800080;">$start</span>) * 1000<span style="color: #000000;">;
        </span><span style="color: #0000ff;">echo</span> "the time2 is ".(int)<span style="color: #800080;">$use_time</span>."ms\n"<span style="color: #000000;">;
};

</span><span style="color: #008000;">//</span><span style="color: #008000;">根据文档的说明 当一个生成器被调用的时候,它返回一个可以被遍历的对象.当你遍历这个对象的时候
//PHP 将会在每次需要值的时候调用生成器函数,
//也就是说此时并没有真的调用$handler中定义的函数。而是返回了一个生成器</span>
<span style="color: #800080;">$generator</span> = <span style="color: #008080;">call_user_func_array</span>(<span style="color: #800080;">$handler</span>,<span style="color: #0000ff;">array</span><span style="color: #000000;">());

</span><span style="color: #0000ff;">if</span> (<span style="color: #800080;">$generator</span> && <span style="color: #800080;">$generator</span><span style="color: #000000;"> instanceof \Generator) {

    </span><span style="color: #008000;">//</span><span style="color: #008000;">当对生成器进行迭代的时候,才会真正的调用该$handler中定义的函数</span>
    <span style="color: #0000ff;">if</span> (<span style="color: #800080;">$generator</span>-><span style="color: #008080;">current</span>() === <span style="color: #0000ff;">false</span><span style="color: #000000;">) {
        </span><span style="color: #008000;">/*</span><span style="color: #008000;">**do some thing*</span><span style="color: #008000;">*/</span><span style="color: #000000;">
    }
}</span>
Nach dem Login kopieren

生成器也可以通过引用来使用

<span style="color: #008000;">/*</span><span style="color: #008000;">*
 * 使用引用来生成值
 </span><span style="color: #008000;">*/</span>
<span style="color: #0000ff;">function</span> &<span style="color: #000000;">gen_reference() {
    </span><span style="color: #800080;">$value</span> = 3<span style="color: #000000;">;

    </span><span style="color: #0000ff;">while</span> (<span style="color: #800080;">$value</span> > 0<span style="color: #000000;">) {
        yield </span><span style="color: #800080;">$value</span><span style="color: #000000;">;
    }
}
</span><span style="color: #008000;">/*</span><span style="color: #008000;"> 
 * 我们可以在循环中修改$number的值,而生成器是使用的引用值来生成,所以gen_reference()内部的$value值也会跟着变化。
 </span><span style="color: #008000;">*/</span>
<span style="color: #0000ff;">foreach</span> (gen_reference() <span style="color: #0000ff;">as</span> &<span style="color: #800080;">$number</span><span style="color: #000000;">) {
    </span><span style="color: #0000ff;">echo</span> (--<span style="color: #800080;">$number</span>).'... '<span style="color: #000000;">;
}</span>
Nach dem Login kopieren

除了通过引用来改变生成器中的数据之外,我们还可以使用send方法传递数据

<span style="color: #0000ff;">function<span style="color: #000000;"> printer() {
    <span style="color: #0000ff;">while (<span style="color: #0000ff;">true<span style="color: #000000;">) {
        <span style="color: #800080;">$string =<span style="color: #000000;"> yield;
        <span style="color: #0000ff;">echo <span style="color: #800080;">$string<span style="color: #000000;">;
    }
}

<span style="color: #800080;">$printer =<span style="color: #000000;"> printer();
<span style="color: #800080;">$printer->send('Hello world!');</span></span></span></span></span></span></span></span></span></span></span></span></span>
Nach dem Login kopieren

但是上面的例子如果没有 while(true),那么无论后面send多少次,该生成器只会执行一次。如此说来,似乎可以用这个来控制本函数调用的最多次数?

除了向里面传递数据之外,还可以throw异常。

<span style="color: #0000ff;">function</span><span style="color: #000000;"> application() {
    </span><span style="color: #0000ff;">while</span> (<span style="color: #0000ff;">true</span><span style="color: #000000;">){
        </span><span style="color: #0000ff;">try</span><span style="color: #000000;"> {
            </span><span style="color: #000000;"> yield;
</span><span style="color: #000000;">
        }</span><span style="color: #0000ff;">catch</span> (<span style="color: #0000ff;">Exception</span> <span style="color: #800080;">$e</span><span style="color: #000000;">){
            </span><span style="color: #0000ff;">echo</span> <span style="color: #800080;">$e</span><span style="color: #000000;">;
        }
    }
}

</span><span style="color: #800080;">$printer</span> =<span style="color: #000000;"> <span style="color: #000000;">application</span>();
</span><span style="color: #800080;">$printer</span>-><span style="color: #0000ff;">throw</span>(<span style="color: #0000ff;">new</span>  <span style="color: #0000ff;">Exception</span>("test"));
Nach dem Login kopieren

 

生成器的嵌套

<span style="color: #008000;">/*</span><span style="color: #008000;">*
 * 在php7中 可以通过yield from 进行嵌套
 </span><span style="color: #008000;">*/</span>
<span style="color: #0000ff;">function</span><span style="color: #000000;"> count_to_ten() {
    yield </span>1<span style="color: #000000;">;
    yield </span>2<span style="color: #000000;">;
    yield from [</span>3, 4<span style="color: #000000;">];
    yield from </span><span style="color: #0000ff;">new</span> ArrayIterator([5, 6<span style="color: #000000;">]);
    yield from seven_eight();
    yield </span>9<span style="color: #000000;">;
    yield </span>10<span style="color: #000000;">;
}

</span><span style="color: #0000ff;">function</span><span style="color: #000000;"> seven_eight() {
    yield </span>7<span style="color: #000000;">;
    yield from eight();
}

</span><span style="color: #0000ff;">function</span><span style="color: #000000;"> eight() {
    yield </span>8<span style="color: #000000;">;
}

</span><span style="color: #800080;">$gen</span> =<span style="color: #000000;"> count_to_ten();
</span><span style="color: #0000ff;">foreach</span> (<span style="color: #800080;">$gen</span> <span style="color: #0000ff;">as</span> <span style="color: #800080;">$num</span><span style="color: #000000;">) {
    </span><span style="color: #0000ff;">echo</span> "<span style="color: #800080;">$num</span> "<span style="color: #000000;">;
}
</span><span style="color: #0000ff;">echo</span> "the return value is ".<span style="color: #800080;">$gen</span>->getReturn();
Nach dem Login kopieren

 

Verwandte Etiketten:
Quelle:php.cn
Erklärung dieser Website
Der Inhalt dieses Artikels wird freiwillig von Internetnutzern beigesteuert und das Urheberrecht liegt beim ursprünglichen Autor. Diese Website übernimmt keine entsprechende rechtliche Verantwortung. Wenn Sie Inhalte finden, bei denen der Verdacht eines Plagiats oder einer Rechtsverletzung besteht, wenden Sie sich bitte an admin@php.cn
Beliebte Empfehlungen
Beliebte Tutorials
Mehr>
Neueste Downloads
Mehr>
Web-Effekte
Quellcode der Website
Website-Materialien
Frontend-Vorlage