Heim  >  Artikel  >  Backend-Entwicklung  >  Machen Sie sich mit den neuen Funktionen von Generatoren in PHP7 vertraut

Machen Sie sich mit den neuen Funktionen von Generatoren in PHP7 vertraut

藏色散人
藏色散人nach vorne
2021-09-03 16:04:001534Durchsuche

Generator-Delegat

Übersetzen Sie einfach die Beschreibung der offiziellen Dokumentation:

PHP7, über den Generator-Delegaten (Ausbeute von), Sie können Delegieren Sie andere Generatoren, iterierbare Objekte und Arrays an äußere Generatoren. Der äußere Generator liefert zunächst nacheinander den delegierten Wert und dann weiterhin den in ihm selbst definierten Wert.

Die Verwendung von yield from kann es uns erleichtern, klarere Generatorverschachtelungen zu schreiben, und Codeverschachtelungsaufrufe sind zum Schreiben komplexer Systeme erforderlich.

Das obige Beispiel:

<?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) {
    ;
}

Das Obige gibt Folgendes aus:

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

Natürlich kann der interne Generator auch von seinem übergeordneten Generator gesendete Informationen oder Ausnahmen akzeptieren, da yield from einen Zwei-Wege-Kanal für die übergeordneten und untergeordneten Generatoren herstellt. Hier ist ohne weiteres ein Beispiel:

<?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

Die Ausgabe ist die gleiche wie im vorherigen Beispiel.

Generator-Rückgabewert

Wenn der Generator iteriert wird oder zum Schlüsselwort „return“ läuft, gibt der Generator einen Wert zurück.
Es gibt zwei Möglichkeiten, diesen Rückgabewert zu erhalten:

  1. Verwenden Sie die Methode $ret = Generator::getReturn().
  2. Verwenden Sie den Ausdruck $ret = yield from Generator().

Das obige Beispiel:

<?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) {
    ;
}

Das Ausgabeergebnis wird nicht veröffentlicht, jeder muss es erraten haben.

Sie können sehen, dass die Kombination aus „Yield from“ und „Return“ dazu führt, dass die Schreibweise von Yield eher dem synchronen Moduscode ähnelt, den wir normalerweise schreiben. Dies ist schließlich einer der Gründe, warum PHP über die Generatorfunktion verfügt.

Ein nicht blockierender Webserver

Bereits im Jahr 2015 wurde ein Artikel „Using Coroutines to Implement Multi-Task Scheduling in PHP“ auf dem Blog von Bruder Niao erneut veröffentlicht. Der Artikel stellt den iterativen Generator Coroutine von PHP5 vor und implementiert einen einfachen nicht blockierenden Webserver. (Siehe den Link am Ende des Artikels)

Jetzt nutzen wir diese beiden neuen Funktionen in PHP7, um diesen Webserver neu zu schreiben, der nur mehr als 100 Zeilen Code benötigt.

Der Code lautet wie folgt:

<?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;
});

Das obige ist der detaillierte Inhalt vonMachen Sie sich mit den neuen Funktionen von Generatoren in PHP7 vertraut. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!

Stellungnahme:
Dieser Artikel ist reproduziert unter:segmentfault.com. Bei Verstößen wenden Sie sich bitte an admin@php.cn löschen