Neue Funktionen von Generatoren in PHP7: Generator-Delegat (yield-from) & Rückgabewert (return-value)

不言
Freigeben: 2023-04-03 15:16:02
Original
2017 Leute haben es durchsucht

Dieser Artikel stellt Ihnen die neuen Funktionen von Generatoren in PHP7 vor: Generatordelegation (Ertrag) und Rückgabewert (Return-Value). Ich hoffe, er hilft Ihnen Du.

Generator-Delegierter

Übersetzen Sie einfach die Beschreibung der offiziellen Dokumentation:

In PHP7 werden über den Generator-Delegaten (Ertrag von) andere Generatoren, iterierbare Objekte und Arrays werden an äußere Generatoren delegiert. Der äußere Generator liefert zunächst sequentiell 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) {
    ;
}
Nach dem Login kopieren

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
Nach dem Login kopieren

Natürlich kann der interne Generator auch von seinem übergeordneten Generator gesendete Informationen oder Ausnahmen akzeptieren, da yield from ein übergeordneter Generator ist. Untergeordneter Generator Erstellen Sie einen Zwei-Wege-Kanal. 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
Nach dem Login kopieren

Die Ausgabe ist die gleiche wie im vorherigen Beispiel.

Generator-Rückgabewert

Wenn der Generator iteriert wird oder zum Schlüsselwort „return“ läuft, wird ein Wert an den Generator zurückgegeben.
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) {
    ;
}
Nach dem Login kopieren

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

Sie können sehen, dass die Kombination von yield from und return das Schreiben von yield eher dem synchronen Moduscode ähnelt, den wir normalerweise schreiben. Schließlich ist dies einer der Gründe, warum PHP über die Generatorfunktion verfügt.

Ein nicht blockierender Webserver

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;
});
Nach dem Login kopieren

Empfohlene verwandte Artikel:

Einfache Analyse von PHP-Generatoren

Das obige ist der detaillierte Inhalt vonNeue Funktionen von Generatoren in PHP7: Generator-Delegat (yield-from) & Rückgabewert (return-value). Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!

Verwandte Etiketten:
Quelle:php.cn
Erklärung dieser Website
Der Inhalt dieses Artikels wird freiwillig von Internetnutzern beigesteuert und das Urheberrecht liegt beim ursprünglichen Autor. Diese Website übernimmt keine entsprechende rechtliche Verantwortung. Wenn Sie Inhalte finden, bei denen der Verdacht eines Plagiats oder einer Rechtsverletzung besteht, wenden Sie sich bitte an admin@php.cn
Beliebte Tutorials
Mehr>
Neueste Downloads
Mehr>
Web-Effekte
Quellcode der Website
Website-Materialien
Frontend-Vorlage