ホームページ php教程 php手册 php生成器的使用 - coder5

php生成器的使用 - coder5

May 20, 2016 am 11:40 AM

按照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>
ログイン後にコピー

如果需要在生成器中指定下标 可以 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>
ログイン後にコピー

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

<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>
ログイン後にコピー

除了通过引用来改变生成器中的数据之外,我们还可以使用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>
ログイン後にコピー

但是上面的例子如果没有 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"));
ログイン後にコピー

 

生成器的嵌套

<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();
ログイン後にコピー

 

このウェブサイトの声明
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。

ホットAIツール

Undresser.AI Undress

Undresser.AI Undress

リアルなヌード写真を作成する AI 搭載アプリ

AI Clothes Remover

AI Clothes Remover

写真から衣服を削除するオンライン AI ツール。

Undress AI Tool

Undress AI Tool

脱衣画像を無料で

Clothoff.io

Clothoff.io

AI衣類リムーバー

AI Hentai Generator

AI Hentai Generator

AIヘンタイを無料で生成します。

ホットツール

メモ帳++7.3.1

メモ帳++7.3.1

使いやすく無料のコードエディター

SublimeText3 中国語版

SublimeText3 中国語版

中国語版、とても使いやすい

ゼンドスタジオ 13.0.1

ゼンドスタジオ 13.0.1

強力な PHP 統合開発環境

ドリームウィーバー CS6

ドリームウィーバー CS6

ビジュアル Web 開発ツール

SublimeText3 Mac版

SublimeText3 Mac版

神レベルのコード編集ソフト(SublimeText3)