PHP7中產生器的新特性:產生器委託( yield-from )&傳回值(return-value)

來源:互聯網
上載者:User
這篇文章給大家介紹的內容是關於PHP7中產生器的新特性:產生器委託( yield-from )&傳回值(return-value),有一定的參考價值,有需要的朋友可以參考一下,希望對你有所協助。

產生器委託

簡單地翻譯官方文檔的描述:

PHP7中,通過產生器委託(yield from),可以將其他產生器、可迭代的對象、數組委託給外層產生器。外層的產生器會先順序 yield 委託出來的值,然後繼續 yield 本身中定義的值。

利用 yield from 可以方便我們編寫比較清晰產生器嵌套,而代碼嵌套調用是編寫複雜系統所必需的。
上例子:

<?phpfunction echoTimes($msg, $max) {    for ($i = 1; $i <= $max; ++$i) {        echo "$msg iteration $i\n";        yield;    }} function task() {    yield from echoTimes('foo', 10); // print foo ten times    echo "---\n";    yield from echoTimes('bar', 5); // print bar five times}foreach (task() as $item) {    ;}

以上將輸出:

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

自然,內部產生器也可以接受它的父產生器發送的資訊或者異常,因為 yield from 為父子產生器建立一個雙向的通道。不多說,上例子:

<?phpfunction echoMsg($msg) {    while (true) {        $i = yield;        if($i === null){            break;        }        if(!is_numeric($i)){            throw new Exception("Hoo! must give me a number");        }        echo "$msg iteration $i\n";    }}function task2() {    yield from echoMsg('foo');    echo "---\n";    yield from echoMsg('bar');}$gen = task2();foreach (range(1,10) as $num) {    $gen->send($num);}$gen->send(null);foreach (range(1,5) as $num) {    $gen->send($num);}//$gen->send("hello world"); //try it ,gay

輸出和上個例子是一樣的。

產生器傳回值

如果產生器被迭代完成,或者運行到 return 關鍵字,是會給這個產生器傳回值的。
可以有兩種方法擷取這個傳回值:

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

  2. 使用 $ret = yield from Generator() 運算式。

上例子:

<?phpfunction echoTimes($msg, $max) {    for ($i = 1; $i <= $max; ++$i) {        echo "$msg iteration $i\n";        yield;    }    return "$msg the end value : $i\n";}function task() {    $end = yield from echoTimes('foo', 10);    echo $end;    $gen = echoTimes('bar', 5);    yield from $gen;    echo $gen->getReturn();}foreach (task() as $item) {    ;}

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

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

一個非阻塞的web伺服器

現在我們利用 PHP7 中的這兩個新特性重寫這個 網頁伺服器,只需要 100 多行代碼。

代碼如下:

<?phpclass CoSocket{    protected $masterCoSocket = null;    public $socket;    protected $handleCallback;    public $streamPoolRead = [];    public $streamPoolWrite = [];    public function __construct($socket, CoSocket $master = null)    {        $this->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...\n";        $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 = <<<RESHTTP/1.1 200 OKContent-Type: text/plainContent-Length: 12Connection: closehello world!RES;    return $response;});
相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.