成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專欄INFORMATION COLUMN

PHP7中生成器的新特性 yield-from && return-values

pinecone / 3198人閱讀

摘要:生成器委托簡(jiǎn)單地翻譯官方文檔的描述中,通過生成器委托,可以將其他生成器可迭代的對(duì)象數(shù)組委托給外層生成器。外層的生成器會(huì)先順序委托出來的值,然后繼續(xù)本身中定義的值。文章介紹了的迭代生成器,協(xié)程,并實(shí)現(xiàn)了一個(gè)簡(jiǎn)單的非阻塞服務(wù)器。

生成器委托

簡(jiǎn)單地翻譯官方文檔的描述:

PHP7中,通過生成器委托(yield from),可以將其他生成器、可迭代的對(duì)象、數(shù)組委托給外層生成器。外層的生成器會(huì)先順序 yield 委托出來的值,然后繼續(xù) yield 本身中定義的值。

利用 yield from 可以方便我們編寫比較清晰生成器嵌套,而代碼嵌套調(diào)用是編寫復(fù)雜系統(tǒng)所必需的。
上例子:


以上將輸出:

foo iteration 1
foo iteration 2
foo iteration 3
foo iteration 4
foo iteration 5
foo iteration 6
foo iteration 7
foo iteration 8
foo iteration 9
foo iteration 10
---
bar iteration 1
bar iteration 2
bar iteration 3
bar iteration 4
bar iteration 5

自然,內(nèi)部生成器也可以接受它的父生成器發(fā)送的信息或者異常,因?yàn)?yield from 為父子生成器建立一個(gè)雙向的通道。不多說,上例子:

send($num);
}
$gen->send(null);
foreach (range(1,5) as $num) {
    $gen->send($num);
}
//$gen->send("hello world"); //try it ,gay

輸出和上個(gè)例子是一樣的。

生成器返回值

如果生成器被迭代完成,或者運(yùn)行到 return 關(guān)鍵字,是會(huì)給這個(gè)生成器返回值的。
可以有兩種方法獲取這個(gè)返回值:

使用 $ret = Generator::getReturn() 方法。

使用 $ret = yield from Generator() 表達(dá)式。

上例子:

getReturn();
}

foreach (task() as $item) {
    ;
}

輸出結(jié)果就不貼了,想必大家都猜到。

可以看到 yield from 和 return 結(jié)合使得 yield 的寫法更像平時(shí)我們寫的同步模式的代碼了,畢竟,這就是 PHP 出生成器特性的原因之一呀。

一個(gè)非阻塞的web服務(wù)器

時(shí)間回到2015年,鳥哥博客上轉(zhuǎn)載的一篇《 在PHP中使用協(xié)程實(shí)現(xiàn)多任務(wù)調(diào)度》。文章介紹了PHP5 的迭代生成器,協(xié)程,并實(shí)現(xiàn)了一個(gè)簡(jiǎn)單的非阻塞 web 服務(wù)器。(鏈接見文末引用)

現(xiàn)在我們利用 PHP7 中的這兩個(gè)新特性重寫這個(gè) web 服務(wù)器,只需要 100 多行代碼。

代碼如下:

socket = $socket;
        $this->masterCoSocket = $master ?? $this;
    }

    public function accept()
    {
        $isSelect = yield from $this->onRead();
        $acceptS = null;
        if ($isSelect && $as = stream_socket_accept($this->socket, 0)) {
            $acceptS = new CoSocket($as, $this);
        }
        return $acceptS;
    }

    public function read($size)
    {
        yield from $this->onRead();
        yield ($data = fread($this->socket, $size));
        return $data;
    }

    public function write($string)
    {
        yield from $this->onWriter();
        yield fwrite($this->socket, $string);
    }

    public function close()
    {
        unset($this->masterCoSocket->streamPoolRead[(int)$this->socket]);
        unset($this->masterCoSocket->streamPoolWrite[(int)$this->socket]);
        yield ($success = @fclose($this->socket));
        return $success;
    }

    public function onRead($timeout = null)
    {
        $this->masterCoSocket->streamPoolRead[(int)$this->socket] = $this->socket;
        $pool = $this->masterCoSocket->streamPoolRead;
        $rSocks = [];
        $wSocks = $eSocks = null;
        foreach ($pool as $item) {
            $rSocks[] = $item;
        }
        yield ($num = stream_select($rSocks, $wSocks, $eSocks, $timeout));
        return $num;
    }

    public function onWriter($timeout = null)
    {
        $this->masterCoSocket->streamPoolWrite[(int)$this->socket] = $this->socket;
        $pool = $this->masterCoSocket->streamPoolRead;
        $wSocks = [];
        $rSocks = $eSocks = null;
        foreach ($pool as $item) {
            $wSocks[] = $item;
        }
        yield ($num = stream_select($rSocks, $wSocks, $eSocks, $timeout));
        return $num;
    }

    public function onRequest()
    {
        /** @var self $socket */
        $socket = yield from $this->accept();
        if (empty($socket)) {
            return false;
        }
        $data = yield from $socket->read(8192);
        $response = call_user_func($this->handleCallback, $data);
        yield from $socket->write($response);
        return yield from $socket->close();
    }

    public static function start($port, callable $callback)
    {
        echo "Starting server at port $port...
";
        $socket = @stream_socket_server("tcp://0.0.0.0:$port", $errNo, $errStr);
        if (!$socket) throw new Exception($errStr, $errNo);
        stream_set_blocking($socket, 0);
        $coSocket = new self($socket);
        $coSocket->handleCallback = $callback;
        function gen($coSocket)
        {
            /** @var self $coSocket */
            while (true) yield from $coSocket->onRequest();
        }
        foreach (gen($coSocket) as $item){};
    }
}

CoSocket::start(8000, function ($data) {
    $response = <<
參考資料

[1] http://www.php.net/manual/zh/...

[2] http://www.laruence.com/2015/...

[3] http://blog.csdn.net/u0101613...

文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/25582.html

相關(guān)文章

  • PHP 7.0 &amp; 7.1 部分新增特性備忘

    摘要:以下分別備忘版本的部分新增特性。而且,在生成器沒有輸出完全時(shí),使用會(huì)報(bào)錯(cuò)。報(bào)錯(cuò)定義常量數(shù)組多聲明數(shù)組解構(gòu)運(yùn)行時(shí)將部分指令轉(zhuǎn)為機(jī)器碼。對(duì)于計(jì)算密集型應(yīng)用有較高的性能提升。 以下分別備忘 PHP 7.0 & 7.1 版本的部分新增特性。 PHP 7.0 ?? 運(yùn)算符 $foo = null; $bar = $foo ?? 123; // 相當(dāng)于 $bar = isset($bar) ? ...

    philadelphia 評(píng)論0 收藏0
  • PHP 生成器入門

    摘要:執(zhí)行語句的唯一目的是結(jié)束生成器執(zhí)行。這就是需要生成器需要有返回值的意義,這也是為何我們將這個(gè)特性加入到中的原因,我們會(huì)將最后執(zhí)行的值作為返回值,但這不是一個(gè)好的解決方案。 本文首發(fā)于 入門 PHP 生成器,轉(zhuǎn)載請(qǐng)注明出處。 PHP 在 5.5 版本中引入了「生成器(Generator)」特性,不過這個(gè)特性并沒有引起人們的注意。在官方的 從 PHP 5.4.x 遷移到 PHP 5.5.x...

    IamDLY 評(píng)論0 收藏0
  • python中的生成器、迭代器、裝飾器分別是什么意思呢?

      python中的生成器、迭代器、裝飾器分別是什么意思呢?具體的含義,一些其具體的用途,下面小編就給大家詳細(xì)的解答下。  一、裝飾器  由于一個(gè)函數(shù)能實(shí)現(xiàn)一種功能,現(xiàn)在想要在不改變其代碼的情況下,讓這個(gè)函數(shù)進(jìn)化一下,即能保持原來的功能,還能有新的"技能",怎么辦?  現(xiàn)已經(jīng)存在一個(gè)自定義的函數(shù)func1  deffunc1():   print('hello,worl...

    89542767 評(píng)論0 收藏0
  • async &amp; await &amp; promise

    摘要:最近項(xiàng)目中用的比較多,所以特地去了解,模仿一下實(shí)現(xiàn)先來看看使用的方法通過是通過使用生成器配合方法模擬的一個(gè)同步操作,這個(gè)技術(shù)有效的避免了傳統(tǒng)回調(diào)和形成的回調(diào)地獄。 最近項(xiàng)目中 asyn & await 用的比較多,所以特地去了解,模仿一下實(shí)現(xiàn)~ 先來看看 使用 async & await 的方法 async function d () { try { const a = a...

    Dean 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

最新活動(dòng)
閱讀需要支付1元查看
<