Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- <?php declare(strict_types = 1);
- $database = new Database();
- // This is know as "continuation passing style". Each asynchronous function call accepts a callback which is
- // invoked with the results of the operation.
- // This reads in the order in which things happen, but clearly it's less than ideal because our indentation
- // level grows with each async operation - and all we did here is fetch some database results.
- // Anyone who has worked with Javascript will be familair
- $server = new HttpServer(function(Request $request, Response $response) use($database) {
- if ($request->getPath() !== '/foo/ids') {
- $response->setResponseCode(404);
- $response->send();
- return;
- }
- // <focus on this section>
- $database->query("SELECT id FROM foo", function(ResultSet $resultSet) use($response) {
- $ids = [];
- $resultSet->forEach(function(Result $result) use(&$ids, $response) {
- $ids[] = $result->getColumn('id');
- if ($result->isLast()) {
- $response->send(json_encode($ids));
- }
- });
- });
- // </focus on this section>
- });
- $server->start();
- // Alternatively we can get rid of the indentation level by defining each step as a function. Let's group those
- // definitions together in a class.
- // We'll assume that routing is still dealt with at the entry point, and the job of this class is just to build a
- // response to the /foo/ids endpoint.
- class FooIdsRequestHandler
- {
- private $database;
- private $request;
- private $response;
- private $ids = [];
- function __construct(Database $database, Request $request, Response $response)
- {
- $this->database = $database;
- $this->request = $request;
- $this->response = $response;
- }
- function handle()
- {
- $this->database->query("SELECT id FROM foo", [$this, 'onDbResultSet']);
- }
- function onDbResultSet(ResultSet $resultSet)
- {
- $resultSet->forEach([$this, 'onDbResult']);
- }
- function onDbResult(Result $result)
- {
- $this->ids[] = $result->getColumn('id');
- if ($result->isLast()) {
- $this->response->send(json_encode($this->ids));
- }
- }
- }
- // This is an improvement but it's still not great. We have a 33 line class definition which represents a fairly
- // trivial routine - and it doesn't even include any error handling. We also can't easily see the order of execution
- // of those methods, there's a very high overhead to understanding the code.
- // Take a step back for a second an think about what that code would look like if it were synchronous:
- $resultSet = $database->query("SELECT id FROM foo");
- $ids = [];
- while ($result = $resultSet->fetch()) {
- $ids[] = $result->getColumn('id');
- }
- $response->send(json_encode($this->ids));
- // this code is short and easy to comprehend because it's linear, but it's also synchronous so it has a high cost if we
- // want to support a lot of concurrency. Our asynchronous code solves that concurrency problem because it's powered by
- // an event loop, but asynchronous code is non-linear and harder to understand.
- // talk about Generator, look at the parts of it that are not Iterator methods, working towards this code at the end:
- $resultSet = yield $database->query("SELECT id FROM foo");
- $ids = [];
- while ($result = yield $resultSet->fetch()) {
- $ids[] = $result->getColumn('id');
- }
- $response->send(json_encode($this->ids));
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement