Let's talk about how to use PHP generator
PHP introduced the "Generator" feature in version 5.5, but this feature did not attract people's attention. In the official migration from PHP 5.4.x to PHP 5.5.x, it is introduced that it can implement iterator (Iterator) in a simple way. But beyond that, in what scenarios can generators be used?
Generator implementation is completed through the yield keyword. Generators provide a simple way to implement iterators with almost no additional overhead or the complexity of implementing iterators through classes that implement the iterator interface.
The documentation provides a simple example demonstrating this simple iterator, please look at the following code:
function xrange($start, $limit, $step = 1) { for ($i = $start; $i <= $limit; $i += $step) { yield $i; } }
Let's compare it to an array without iterator support:
foreach xrange($start, $limit, $step = 1) { $elements = []; for ($i = $start; $i <= $limit; $i += $step) { $elements[] = $i; } return $elements; }
Both versions of the function support foreach iterating over all elements:
foreach (xrange(1, 100) as $i) { print $i . PHP_EOL; }
So besides a shorter function definition, what else can we get? yield What exactly did you do? Why can data be returned when the first function is defined, even without the return statement?
Let’s start with the return value. Generators are a very special function in PHP. When a function contains yield, then the function is no longer an ordinary function, it always returns a "Generator" instance. The generator implements the Iterator interface, which is why it is capable of foreach traversal.
Next I use the methods in the Iterator interface to rewrite the previous foreach loop. You can view the results at 3v4l.org.
$generator = xrange(1, 100); while($generator->valid()) { print $generator->current() . PHP_EOL; $generator->next(); }
We can clearly see that generators are a more advanced technology. Now let us write a new generator example to better understand how it is processed inside the generator.
function foobar() { print 'foobar - start' . PHP_EOL; for ($i = 0; $i < 5; $i++) { print 'foobar - yielding...' . PHP_EOL; yield $i; print 'foobar - continued...' . PHP_EOL; } print 'foobar - end' . PHP_EOL; } $generator = foobar(); print 'Generator created' . PHP_EOL; while ($generator->valid()) { print "Getting current value from the generator..." . PHP_EOL; print $generator->current() . PHP_EOL; $generator->next(); }
Huh? Why is Generator created printed first? This is because the generator does nothing until it is used. In the above example, it is the code $generator->valid()** that starts executing the generator. We see that the generator runs until the first **yield** and returns the control flow to the caller **$generator->valid(). $generator->next() When called, the generator execution is resumed and stops running again at the next yield, and so on until there are no more yield until. We now have terminal functions that can perform pause and resume at any yield. This feature allows writing defer functions required by the client.
You can create a function that reads all users from the GitHub API. Pagination is supported, but you can hide these details and fetch the next page of data only when needed. You can use yield to obtain each user data from the current page. Until all users on the current page are obtained, you can then obtain the next page of data.
Generator created foobar - start foobar - yielding... Getting current value from the generator... 1 foobar - continued foobar - yielding... Getting current value from the generator... 2 foobar - continued foobar - yielding... Getting current value from the generator... 3 foobar - continued foobar - yielding... Getting current value from the generator... 4 foobar - continued foobar - yielding... Getting current value from the generator... 5 foobar - continued foobar - end
The client can iterate out all users or stop the traversal at any time.
Using generators as iterators is really boring
Yes, you have the right idea. All the explanations I have given above can be obtained by anyone from the PHP documentation. But as an iterator, these uses don't even use half of its powerful capabilities. Generators also provide send() and throw() functions that are not part of the Iterator interface. We talked earlier about the ability to pause and resume generator execution. When you need to restore the generator, you can not only use the Generator::next() method, but also use Generator::send() and Generator::throw() method.
Generator::send() allows you to specify the return value of yield, while Generator::throw() allows you to yield throws an exception. Through these methods we can not only get data from the generator, but also send new data to the generator.
Let's look at a Logger log example taken from Cooperative multitasking using coroutines (highly recommended to read this article).
class GitHubClient { function getUsers(): Iterator { $uri = '/users'; do { $response = $this->get($uri); foreach ($response->items as $user) { yield $user; } $uri = $response->nextUri; } while($uri !== null); } }
yield is used as an expression here. When we send data, the data is returned from yield and then passed as a parameter to fwrite().
To be honest, this example is useless in actual projects. It is only used to demonstrate the usage principle of Generator::send(), but just being able to send data does not have much effect. It would be different if there was a class that supported ordinary functions.
使用生成器的乐趣来自于通过 yield 创建数据,然后由「生成器执行程序(generator runner)」依据这个数据来处理业务,然后再继续执行生成器。这就是「协程(coroutines)」和「状态流解析器(stateful streaming parsers)」实例。在讲解协程和状态流解析器之前,我们快速浏览一下如何在生成器中返回数据,我们还没有将接触这方面的知识。从 PHP 5.5 开始我们可以在生成器内部使用 return; 语句,但是不能返回任何值。执行 return; 语句的唯一目的是结束生成器执行。
不过从 PHP 7.0 起支持返回值。这个功能在用于迭代时可能有些奇怪,但是在其他使用场景如协程时将非常有用,例如,当我们在执行一个生成器时我们可以依据返回值处理,而无需直接对生成器进行操作。下一节我们将讲解 return 语句在协程中的使用。
异步生成器
Amp 是一款 PHP 异步编程的框架。支持异步协程功能,本质上是等待处理结果的占位符。「生成器执行程序」为 Coroutine类。它会订阅异步生成器(yielded promise),当有执行结果可用时则继续生成器处理。如果处理失败,则会抛出异常给生成器。你可以到 amphp/amp 版本库查看实现细节。在 Amp 中的 Coroutine 本身就是一个 Promise。如果这个协程抛出未经捕获的异常,这个协程就执行失败了。如果解析成功,那么就返回一个值。这个值看起来和普通函数的返回值并无二致,只不过它处于异步执行环境中。这就是需要生成器需要有返回值的意义,这也是为何我们将这个特性加入到 PHP 7.0 中的原因,我们会将最后执行的yield 值作为返回值,但这不是一个好的解决方案。
Amp 可以像编写阻塞代码一样编写非阻塞代码,同时允许在同一进程中执行其它非阻塞事件。一个使用场景是,同时对一个或多个第三方 API 并行的创建多个 HTTP 请求,但不限于此。得益于事件循环,可以同时处理多个 I/O 处理,而不仅仅是只能处理多个 HTTP请求这类操作。
Loop::run(function() { $uris = [ "https://google.com/", "https://github.com/", "https://stackoverflow.com/", ]; $client = new Amp\Artax\DefaultClient; $promises = []; foreach ($uris as $uri) { $promises[$uri] = $client->request($uri); } $responses = yield $promises; foreach ($responses as $uri => $response) { print $uri . " - " . $response->getStatus() . PHP_EOL; } });
但是,拥有异步功能的协程并非只能够在 yield 右侧出现变量,还可以在它的左侧。这就是我们前面提到的解析器。
$parse = new Parser((function(){ while (true) { $line = yield "\r\n"; if (trim($line) === "") { continue; } print "New item: {$line}" . PHP_EOL; } })()); for ($i = 0; $i < 100; $i++) { $parser->push("bar\r"); $parser->push("\nfoo"); }
解析器会缓存所有输入直到接收的是 rn。这类生成器解析器并不能简化简单协议处理(如换行分隔符协议),但是对于复杂的解析器,如在服务器解析 HTTP 请求的 Aerys。
相关推荐:
The above is the detailed content of Let's talk about how to use PHP generator. For more information, please follow other related articles on the PHP Chinese website!

Hot AI Tools

Undresser.AI Undress
AI-powered app for creating realistic nude photos

AI Clothes Remover
Online AI tool for removing clothes from photos.

Undress AI Tool
Undress images for free

Clothoff.io
AI clothes remover

Video Face Swap
Swap faces in any video effortlessly with our completely free AI face swap tool!

Hot Article

Hot Tools

Notepad++7.3.1
Easy-to-use and free code editor

SublimeText3 Chinese version
Chinese version, very easy to use

Zend Studio 13.0.1
Powerful PHP integrated development environment

Dreamweaver CS6
Visual web development tools

SublimeText3 Mac version
God-level code editing software (SublimeText3)

Hot Topics











PHP and Python each have their own advantages, and choose according to project requirements. 1.PHP is suitable for web development, especially for rapid development and maintenance of websites. 2. Python is suitable for data science, machine learning and artificial intelligence, with concise syntax and suitable for beginners.

PHP is widely used in e-commerce, content management systems and API development. 1) E-commerce: used for shopping cart function and payment processing. 2) Content management system: used for dynamic content generation and user management. 3) API development: used for RESTful API development and API security. Through performance optimization and best practices, the efficiency and maintainability of PHP applications are improved.

PHP is a scripting language widely used on the server side, especially suitable for web development. 1.PHP can embed HTML, process HTTP requests and responses, and supports a variety of databases. 2.PHP is used to generate dynamic web content, process form data, access databases, etc., with strong community support and open source resources. 3. PHP is an interpreted language, and the execution process includes lexical analysis, grammatical analysis, compilation and execution. 4.PHP can be combined with MySQL for advanced applications such as user registration systems. 5. When debugging PHP, you can use functions such as error_reporting() and var_dump(). 6. Optimize PHP code to use caching mechanisms, optimize database queries and use built-in functions. 7

PHP is still dynamic and still occupies an important position in the field of modern programming. 1) PHP's simplicity and powerful community support make it widely used in web development; 2) Its flexibility and stability make it outstanding in handling web forms, database operations and file processing; 3) PHP is constantly evolving and optimizing, suitable for beginners and experienced developers.

PHP and Python each have their own advantages, and the choice should be based on project requirements. 1.PHP is suitable for web development, with simple syntax and high execution efficiency. 2. Python is suitable for data science and machine learning, with concise syntax and rich libraries.

PHP and Python have their own advantages and disadvantages, and the choice depends on project needs and personal preferences. 1.PHP is suitable for rapid development and maintenance of large-scale web applications. 2. Python dominates the field of data science and machine learning.

PHP is suitable for web development, especially in rapid development and processing dynamic content, but is not good at data science and enterprise-level applications. Compared with Python, PHP has more advantages in web development, but is not as good as Python in the field of data science; compared with Java, PHP performs worse in enterprise-level applications, but is more flexible in web development; compared with JavaScript, PHP is more concise in back-end development, but is not as good as JavaScript in front-end development.

PHP is mainly procedural programming, but also supports object-oriented programming (OOP); Python supports a variety of paradigms, including OOP, functional and procedural programming. PHP is suitable for web development, and Python is suitable for a variety of applications such as data analysis and machine learning.
