Maison >développement back-end >tutoriel php >Nouvelles fonctionnalités des générateurs en PHP7 : délégué du générateur (yield-from) et valeur de retour (return-value)

Nouvelles fonctionnalités des générateurs en PHP7 : délégué du générateur (yield-from) et valeur de retour (return-value)

不言
不言original
2018-08-04 09:36:132070parcourir

Cet article vous présente les nouvelles fonctionnalités des générateurs en PHP7 : délégation du générateur (rendement) et valeur de retour (valeur de retour). Les amis dans le besoin peuvent s'y référer. toi.

Délégué générateur

Traduisez simplement la description de la documentation officielle :

En PHP7, via le délégué générateur (yield from), d'autres Générateurs, les objets itérables et les tableaux délèguent à des générateurs externes. Le générateur externe produira d’abord la valeur déléguée de manière séquentielle, puis continuera à produire la valeur définie en lui-même.

L'utilisation de rendement from peut nous permettre d'écrire plus facilement une imbrication de générateur plus claire, et les appels d'imbrication de code sont nécessaires pour écrire des systèmes complexes.
L'exemple ci-dessus :

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

Ce qui précède affichera :

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

Naturellement, le générateur interne peut également accepter des informations ou des exceptions envoyées par son générateur parent, car le rendement de Établissez un canal bidirectionnel pour les générateurs parent-enfant. Sans plus tarder, voici un exemple :

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

Le résultat est le même que l’exemple précédent.

Valeur de retour du générateur

Si le générateur est itéré ou exécute le mot-clé return, une valeur sera renvoyée au générateur.
Il existe deux façons d'obtenir cette valeur de retour :

  1. Utilisez la méthode $ret = Generator::getReturn().

  2. Utilisez $ret = rendement de l'expression Generator().

L'exemple ci-dessus :

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

Le résultat de la sortie ne sera pas publié, tout le monde doit l'avoir deviné.

Vous pouvez voir que la combinaison de rendement from et return rend l'écriture de rendement plus proche du code en mode synchrone que nous écrivons habituellement. Après tout, c'est l'une des raisons pour lesquelles PHP dispose de la fonctionnalité générateur.

Un serveur web non bloquant

Nous utilisons désormais ces deux nouvelles fonctionnalités de PHP7 pour réécrire ce serveur web, qui ne nécessite que plus de 100 lignes de code.

Le code est le suivant :

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

Articles connexes recommandés :

Analyse simple des générateurs PHP

Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

Déclaration:
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn