Rumah  >  Artikel  >  pembangunan bahagian belakang  >  Membawa anda memahami ciri baharu penjana dalam PHP7

Membawa anda memahami ciri baharu penjana dalam PHP7

藏色散人
藏色散人ke hadapan
2021-09-03 16:04:001534semak imbas

Perwakilan penjana

Terjemahkan huraian dokumentasi rasmi:

Dalam PHP7, melalui delegasi penjana (hasil daripada), penjana lain, objek boleh lelar dan tatasusunan boleh diwakilkan kepada penjana luar. Penjana luar akan mula-mula menghasilkan nilai yang diwakilkan secara berurutan, dan kemudian terus menghasilkan nilai yang ditakrifkan dengan sendirinya.

Menggunakan hasil daripada boleh memudahkan kami menulis sarang penjana yang lebih jelas, dan panggilan sarang kod diperlukan untuk menulis sistem yang kompleks.

Contoh di atas:

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

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

Di atas akan mengeluarkan:

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

Sudah tentu, penjana dalaman juga boleh menerima maklumat atau pengecualian yang dihantar oleh penjana induknya , Kerana hasil daripada mewujudkan saluran dua hala untuk penjana ibu bapa-anak. Tanpa berlengah lagi, berikut ialah contoh:

<?php
function 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(&#39;foo&#39;);
    echo "---\n";
    yield from echoMsg(&#39;bar&#39;);
}
$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

Keluaran adalah sama seperti contoh sebelumnya.

Nilai pulangan penjana

Jika penjana diulang atau berjalan ke kata kunci pulangan, penjana akan mengembalikan nilai.
Terdapat dua cara untuk mendapatkan nilai pulangan ini:

  1. Gunakan kaedah $ret = Generator::getReturn().
  2. Gunakan $ret = hasil daripada ungkapan Generator().

Contoh di atas:

<?php
function 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(&#39;foo&#39;, 10);
    echo $end;
    $gen = echoTimes(&#39;bar&#39;, 5);
    yield from $gen;
    echo $gen->getReturn();
}

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

Hasil output tidak akan disiarkan, semua orang mesti menekanya.

Anda dapat melihat bahawa gabungan hasil daripada dan pulangan menjadikan penulisan hasil lebih seperti kod mod segerak yang biasa kita tulis Lagipun, ini adalah salah satu sebab PHP mempunyai ciri penjana.

Pelayan web yang tidak menyekat

Pada tahun 2015, artikel "Menggunakan coroutine untuk melaksanakan penjadualan berbilang tugas dalam PHP" telah disiarkan semula di blog Brother Niao . Artikel ini memperkenalkan penjana lelaran PHP5, coroutine, dan melaksanakan pelayan web tanpa sekatan yang mudah. (Lihat pautan di penghujung artikel)

Kini kami menggunakan dua ciri baharu ini dalam PHP7 untuk menulis semula pelayan web ini, yang hanya memerlukan lebih daripada 100 baris kod.

Kodnya adalah seperti berikut:

<?php

class 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 = <<<RES
HTTP/1.1 200 OK
Content-Type: text/plain
Content-Length: 12
Connection: close

hello world!
RES;
    return $response;
});

Atas ialah kandungan terperinci Membawa anda memahami ciri baharu penjana dalam PHP7. Untuk maklumat lanjut, sila ikut artikel berkaitan lain di laman web China PHP!

Kenyataan:
Artikel ini dikembalikan pada:segmentfault.com. Jika ada pelanggaran, sila hubungi admin@php.cn Padam