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('foo', 10); // print foo ten times echo "---\n"; yield from echoTimes('bar', 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('foo'); echo "---\n"; yield from echoMsg('bar'); } $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 :
Utilisez la méthode $ret = Generator::getReturn().
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('foo', 10); echo $end; $gen = echoTimes('bar', 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!