This article introduces to you about the new features of the generator in PHP7: Generator delegate (Yield-from) & return Value (Return-value), there is a certain reference value, the need for friends can refer to, I hope to help you.
Builder delegate
Simply translate the description of the official document:
In PHP7, with the generator delegate (yield from), you can delegate other generators, objects that can be iterated, and arrays to the outer generator. The outer generator orders the value of the yield delegate first, and then proceeds to the value defined in the yield itself.
Using yield from allows us to write relatively clear generator nesting, and code nesting calls are required to write complex systems.
above example:
<?phpfunction echotimes ($msg, $max) {for ($i = 1; $i <= $max; + + $i) { echo "$msg iteration $i \ n"; yield; }} function Task () { yield from echotimes (' foo ', ten);//print Foo ten times echo "---\ n"; Yield from echotimes (' Bar ', 5); Print Bar five Times}foreach (Task () as $item) { ;}
The above will output:
Foo Iteration 1foo Iteration 2foo Iteration 3foo Iteration 4foo Iteration 5foo Iteration 6foo Iteration 7foo Iteration 8fo o Iteration 9foo Iteration---bar iteration 1bar Iteration 2bar Iteration 3bar Iteration 4bar Iteration 5
Naturally, the internal generator can also accept information or exceptions sent by its parent generator, because yield from creates a two-way channel for the parent-child generator. Not much to say, on the example:
<?phpfunction 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
The output is the same as the previous example.
Generator return value
If the generator is completed by iteration, or if it runs to the return keyword, it will return a value to the generator.
There are two ways to get this return value:
Use the $ret = Generator::getreturn () method.
Use the $ret = yield from Generator () expression.
above example:
<?phpfunction 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 ', ten); echo $end; $gen = Echotimes (' Bar ', 5); Yield from $gen; echo $gen->getreturn ();} foreach (Task () as $item) { ;}
The output will not be posted, presumably we all guessed.
You can see that yield from and return combine to make the writing of yield more like the usual code of the synchronization mode we write, after all, this is one of the reasons for the PHP generator characteristics.
A non-blocking Web server
Now we are using these two new features in PHP7 to rewrite this web server with just over 100 lines of code.
The code is as follows:
<?phpclass 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; The 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); The 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->SOC KET] = $this->socket; $pool = $this->mastercosocket->streampoolread; $wSocks = []; $rSocks = $eSocks = null; foreach ($pool as $item) {$wSocks [] = $item; The yield ($num = Stream_select ($rSocks, $wSocks, $eSocks, $timeout)); return $num; The Public Function onrequest () {/** @var the 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->on Request (); } foreach (Gen ($coSocket) as $itEM) {}; }}cosocket::start (8000, function ($data) {$response = <<<reshttp/1.1 okcontent-type:text/plaincontent-le Ngth:12connection:closehello world! RES; return $response;});