Heim > Backend-Entwicklung > PHP7 > Hauptteil

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

藏色散人
Freigeben: 2023-02-18 08:02:02
nach vorne
1545 Leute haben es durchsucht

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

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

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!

Verwandte Etiketten:
Quelle:segmentfault.com
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