您好,欢迎来到三六零分类信息网!老站,搜索引擎当天收录,欢迎发信息

带你了解PHP7里生成器的新特性

2024/3/19 7:26:27发布13次查看
php7中生成器的新特性 yield-from && return-values生成器委托
简单地翻译官方文档的描述:
php7中,通过生成器委托(yield from),可以将其他生成器、可迭代的对象、数组委托给外层生成器。外层的生成器会先顺序 yield 委托出来的值,然后继续 yield 本身中定义的值。
利用 yield from 可以方便我们编写比较清晰生成器嵌套,而代码嵌套调用是编写复杂系统所必需的。
上例子:
<?phpfunction 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) { ;}
以上将输出:
foo iteration 1foo iteration 2foo iteration 3foo iteration 4foo iteration 5foo iteration 6foo iteration 7foo iteration 8foo iteration 9foo iteration 10---bar iteration 1bar iteration 2bar iteration 3bar iteration 4bar iteration 5
自然,内部生成器也可以接受它的父生成器发送的信息或者异常,因为 yield from 为父子生成器建立一个双向的通道。不多说,上例子:
<?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
输出和上个例子是一样的。
生成器返回值
如果生成器被迭代完成,或者运行到 return 关键字,是会给这个生成器返回值的。
可以有两种方法获取这个返回值:
使用 $ret = generator::getreturn() 方法。使用 $ret = yield from generator() 表达式。上例子:
<?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', 10); echo $end; $gen = echotimes('bar', 5); yield from $gen; echo $gen->getreturn();}foreach (task() as $item) {    ;}
输出结果就不贴了,想必大家都猜到。
可以看到 yield from 和 return 结合使得 yield 的写法更像平时我们写的同步模式的代码了,毕竟,这就是 php 出生成器特性的原因之一呀。
一个非阻塞的web服务器
时间回到2015年,鸟哥博客上转载的一篇《 在php中使用协程实现多任务调度》。文章介绍了php5 的迭代生成器,协程,并实现了一个简单的非阻塞 web 服务器。(链接见文末引用)
现在我们利用 php7 中的这两个新特性重写这个 web 服务器,只需要 100 多行代码。
代码如下:
<?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;    }    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 = << 以上就是带你了解php7里生成器的新特性的详细内容。
该用户其它信息

VIP推荐

免费发布信息,免费发布B2B信息网站平台 - 三六零分类信息网 沪ICP备09012988号-2
企业名录 Product