稀裡糊塗系列之yield前瞻

符權發表於2018-12-06

前言

上一次發了一篇關於閉包中介軟體的文章,只是略微提到一點皮毛(也只理解到了那麼點皮毛)。

將技術知識放到具體的應用場景中,才能更好的理解它。恰巧我前兩天在對一個統計資料指令碼進行升級優化時,算是對 “閉包” 進行了一點點小的應用吧,我後續會單獨發一篇文章談談心得。

今天,說說我學習yield的一些小感受吧。 網上關於yield的示例最多的,就是一個xrange()的實現吧。都爛大街了,我就不按這個套路來了......

首先

來段小白程式碼

function fini()
{
    $x = 'hello';
    yield $x;
}

$res = fini();
echo $res->current();   // hello
複製程式碼

給小白觀眾說明一下吧。yield關鍵字在這裡和return的作用有點像。

區別呢,就是它返回的是一個Generator物件的例項,我這裡呼叫的current()就是它的方法之一。 也就是說,只要一個函式中有yield,那麼呼叫這個函式就會返回Generator。列一下官網手冊:

Generator implements Iterator {
    /* 方法 */
    public mixed current ( void )
    public mixed key ( void )
    public void next ( void )
    public void rewind ( void )
    public mixed send ( mixed $value )
    public void throw ( Exception $exception )
    public bool valid ( void )
    public void __wakeup ( void )
}
複製程式碼

其次

來段高階小白的程式碼

function fini()
{
    $x = 'hello';
    $y = (yield $x);        // [1]
    echo $y;                // [5]
}

$res = fini();              // [2]
echo $res->current();       // [3]

$res->send(' world');       // [4]
複製程式碼

接下就是yield神奇的地方了,他會輸出:

hello world
複製程式碼

讓我們來捋捋這段程式碼,看看到底發生了什麼。

  • First,yield會例項化一個Generator物件(也就是[1]),並且自動呼叫其rewind()方法
  • Second,把生成的Generator例項化賦值給$res[2]
  • Thirty,通過current()獲取當前Generator中儲存(內部指標的位置)的值'hello'並輸出([3]
  • Fouth,通過send()方法,使得程式回到了[1]位置,並且把send()方法的引數賦值給$y並輸出([5]

再次

多來幾個yield

function fini()
{
    $x = 'hello';
    $y = (yield $x);
    echo $y;
    
    yield ' world';
}

$res = fini();
echo $res->current();

$wes = $res->send(' big');
echo $wes;
複製程式碼

最終輸出結果:

hello big wolrd
複製程式碼

最後

我覺得,yield就是一把 “切腸刀”,把函式這根 “香腸” 切成n截,然後依次放到Generator這個 “飯盒”,然後你需要 “吃” 的時候,拿出一截來,但是 “吃” 的時候只能按照放好的次序來 “吃”

比喻可能有不當的地方,做拋磚引玉,希望大佬來斧正。

最最後,安利一波鳥哥的《在PHP中使用協程實現多工排程》,向大佬學習,收益頗多。

相關文章