SlideShare a Scribd company logo
You Got Async
in my PHP!
PRESENTED BY:
Chris Tankersley
Senior PHP Developer Advocate
@dragonmantank
What is
Async?
2
It Depends
3
Procedural
Programming
4
Do this, then this, then this
$t = new Twitter(new HttpClient());
$tweets = $t->getTweets('dragonmantank');
$template = new Template('tweets.php');
echo $template->render([
‘tweets’ => $tweets,
]);
Procedural Programming
• Single Threaded
• Very susceptible to blocking
operations
• Easy to write
5
Make
Twitter
Object
Make
HTTP
Object
Get
Tweets
Read
Template
Render
Template
6
$t = new Twitter(new HttpClient());
$tweets =
$t->getTweets('dragonmantank');
$template = new
Template('tweets.php');
echo $template->render([
‘tweets’ => $tweets,
]);
script.php Call Stack
7
$t = new Twitter(new HttpClient());
$tweets =
$t->getTweets('dragonmantank');
$template = new
Template('tweets.php');
echo $template->render([
‘tweets’ => $tweets,
]);
script.php Call Stack
main()
8
$t = new Twitter(new HttpClient());
$tweets =
$t->getTweets('dragonmantank');
$template = new
Template('tweets.php');
echo $template->render([
‘tweets’ => $tweets,
]);
script.php Call Stack
main()
new HttpClient()
9
$t = new Twitter(new HttpClient());
$tweets =
$t->getTweets('dragonmantank');
$template = new
Template('tweets.php');
echo $template->render([
‘tweets’ => $tweets,
]);
script.php Call Stack
main()
new HttpClient()
require_once 'src/HttpClient.php'
10
$t = new Twitter(new HttpClient());
$tweets =
$t->getTweets('dragonmantank');
$template = new
Template('tweets.php');
echo $template->render([
‘tweets’ => $tweets,
]);
script.php Call Stack
main()
new HttpClient()
11
$t = new Twitter(new HttpClient());
$tweets =
$t->getTweets('dragonmantank');
$template = new
Template('tweets.php');
echo $template->render([
‘tweets’ => $tweets,
]);
script.php Call Stack
main()
new Twitter();
12
$t = new Twitter(new HttpClient());
$tweets =
$t->getTweets('dragonmantank');
$template = new
Template('tweets.php');
echo $template->render([
‘tweets’ => $tweets,
]);
script.php Call Stack
main()
new Twitter();
require_once 'src/Twitter.php'
13
$t = new Twitter(new HttpClient());
$tweets =
$t->getTweets('dragonmantank');
$template = new
Template('tweets.php');
echo $template->render([
‘tweets’ => $tweets,
]);
script.php Call Stack
main()
new Twitter();
require_once 'src/Twitter.php'
getenv('TWITTER_KEY')
14
$t = new Twitter(new HttpClient());
$tweets =
$t->getTweets('dragonmantank');
$template = new
Template('tweets.php');
echo $template->render([
‘tweets’ => $tweets,
]);
script.php Call Stack
main()
new Twitter();
require_once 'src/Twitter.php'
15
$t = new Twitter(new HttpClient());
$tweets =
$t->getTweets('dragonmantank');
$template = new
Template('tweets.php');
echo $template->render([
‘tweets’ => $tweets,
]);
script.php Call Stack
main()
new Twitter();
require_once 'src/Twitter.php'
getenv('TWITTER_SECRET')
16
$t = new Twitter(new HttpClient());
$tweets =
$t->getTweets('dragonmantank');
$template = new
Template('tweets.php');
echo $template->render([
‘tweets’ => $tweets,
]);
script.php Call Stack
main()
new Twitter();
require_once 'src/Twitter.php'
17
$t = new Twitter(new HttpClient());
$tweets =
$t->getTweets('dragonmantank');
$template = new
Template('tweets.php');
echo $template->render([
‘tweets’ => $tweets,
]);
script.php Call Stack
main()
new Twitter();
18
$t = new Twitter(new HttpClient());
$tweets =
$t->getTweets('dragonmantank');
$template = new
Template('tweets.php');
echo $template->render([
‘tweets’ => $tweets,
]);
script.php Call Stack
main()
19
$t = new Twitter(new HttpClient());
$tweets =
$t->getTweets('dragonmantank');
$template = new
Template('tweets.php');
echo $template->render([
‘tweets’ => $tweets,
]);
script.php Call Stack
main()
$t->getTweets()
20
$t = new Twitter(new HttpClient());
$tweets =
$t->getTweets('dragonmantank');
$template = new
Template('tweets.php');
echo $template->render([
‘tweets’ => $tweets,
]);
script.php Call Stack
main()
$t->getTweets()
$httpClient->get($url)
21
$t = new Twitter(new HttpClient());
$tweets =
$t->getTweets('dragonmantank');
$template = new
Template('tweets.php');
echo $template->render([
‘tweets’ => $tweets,
]);
script.php Call Stack
main()
$t->getTweets()
22
$t = new Twitter(new HttpClient());
$tweets =
$t->getTweets('dragonmantank');
$template = new
Template('tweets.php');
echo $template->render([
‘tweets’ => $tweets,
]);
script.php Call Stack
main()
23
Wait, how does
PHP avoid
blocking?
24
Wait, how does
PHP avoid
blocking?
Web Servers, like Apache,
are multi-threaded
PHP-FPM spins up
multiple threads for use
Parallel
Computing
Do this, this, and this at the same
time
$reports = [
new DailyBalance(),
new EndOfDay(),
new ProfitLossUpdate(),
];
foreach ($reports as $r) {
$pid = pcntl_fork();
if ($pid === 0) {
$r->run();
exit();
}
}
25
Parallel Programming
• Multiple Threads
• Lets the OS/CPU handle scheduling
• Can be tricky to write
26
Make
Report
Objects
Run Daily
Balance
Report Run End of
Day Report
Run
Profit-Loss
Report
End
27
Main Thread
main()
28
Main Thread
main()
foreach($report)
29
Main Thread
main()
foreach($report)
pcntl_fork()
30
Main Thread
main()
foreach($report)
pcntl_fork()
Daily Balance Thread
main()
31
Main Thread
main()
foreach($report)
pcntl_fork()
Daily Balance Thread
main()
if ($pid > 0)
if ($pid > 0)
32
Main Thread
main()
foreach($report)
pcntl_fork()
Daily Balance Thread
main()
if ($pid > 0)
$r->run()
33
Main Thread
main()
foreach($report)
Daily Balance Thread
main()
if ($pid > 0)
$r->run()
34
Main Thread
main()
foreach($report)
Daily Balance Thread
main()
if ($pid > 0)
$r->run()pcntl_fork()
End Of Day Thread
main()
35
Main Thread
main()
foreach($report)
Daily Balance Thread
main()
if ($pid > 0)
$r->run()pcntl_fork()
End Of Day Thread
main()
if ($pid > 0)
if ($pid > 0)
36
Main Thread
main()
foreach($report)
Daily Balance Thread
main()
if ($pid > 0)
$r->run()pcntl_fork()
End Of Day Thread
main()
if ($pid > 0)
$r->run()
37
Main Thread
main()
foreach($report)
Daily Balance Thread
main()
if ($pid > 0)
$r->run()
End Of Day Thread
main()
if ($pid > 0)
$r->run()
38
Main Thread
main()
foreach($report)
Daily Balance Thread
main()
if ($pid > 0)
$r->run()
End Of Day Thread
main()
if ($pid > 0)
$r->run()pcntl_fork()
39
Main Thread
main()
foreach($report)
Daily Balance Thread
main()
if ($pid > 0)
$r->run()
End Of Day Thread
main()
if ($pid > 0)
$r->run()pcntl_fork()
Profit/Loss Thread
main()
40
Main Thread
main()
foreach($report)
Daily Balance Thread
main()
if ($pid > 0)
$r->run()
End Of Day Thread
main()
if ($pid > 0)
pcntl_fork()
Profit/Loss Thread
main()
if ($pid > 0)
if ($pid > 0)
41
Main Thread
main()
foreach($report)
Daily Balance Thread
main()
if ($pid > 0)
$r->run()
End Of Day Thread
main()
pcntl_fork()
Profit/Loss Thread
main()
if ($pid > 0)
$r->run()
42
Main Thread
main()
foreach($report)
Daily Balance Thread
main()
if ($pid > 0)
$r->run()
Profit/Loss Thread
main()
if ($pid > 0)
$r->run()
43
Main Thread
main()
Daily Balance Thread
main()
if ($pid > 0)
$r->run()
Profit/Loss Thread
main()
if ($pid > 0)
$r->run()
44
Main Thread
main()
Daily Balance Thread
main()
if ($pid > 0)
$r->run()
Profit/Loss Thread
main()
if ($pid > 0)
$r->run()
pcntl_wait()
45
Main Thread
main()
Daily Balance Thread
main()
if ($pid > 0)
$r->run()
Profit/Loss Thread
main()
if ($pid > 0)
$r->run()
pcntl_wait()
46
Main Thread
main()
Daily Balance Thread
main()
if ($pid > 0)
$r->run()
Profit/Loss Thread
main()
if ($pid > 0)pcntl_wait()
47
Main Thread
main()
Daily Balance Thread
main()
if ($pid > 0)
$r->run()
Profit/Loss Thread
main()
pcntl_wait()
48
Main Thread
main()
Daily Balance Thread
main()
if ($pid > 0)
$r->run()
Profit/Loss Thread
pcntl_wait()
49
Main Thread
main()
Daily Balance Thread
main()
if ($pid > 0)
$r->run()
pcntl_wait()
Async
Programming
Try and do this, this, and this, as
simultaneously as possible
$loop = EventLoop::create();
$loop->addEvent(function () {
echo "Function 1" . PHP_EOL;
return rand(1,10);
}, function($num) {
echo "Square: " . ($num * $num) .
PHP_EOL;
});
$loop->addEvent(function () {
echo "Function 2". PHP_EOL;
}, function() {
echo "Function 4" . PHP_EOL;
});
$loop->run();
50
Async Programming
• Single Threaded
• Uses an event loop
• Allows quick executions
between larger blocking
operations
51
Event loop ends
Queue
Empty?
Execute
job
Has
callback?
Add to
queue
Start Event
Loop
Yes
Yes No
No
52
$loop = EventLoop::create();
$loop->addEvent($event1, $callback1);
$loop->addEvent($event2, $callback2);
$loop->run();
eventloop.php Call Stack
main()
53
$loop = EventLoop::create();
$loop->addEvent($event1, $callback1);
$loop->addEvent($event2, $callback2);
$loop->run();
eventloop.php Call Stack
main()
54
$loop = EventLoop::create();
$loop->addEvent($event1, $callback1);
$loop->addEvent($event2, $callback2);
$loop->run();
eventloop.php Call Stack
main()
EventLoop::create()
55
$loop = EventLoop::create();
$loop->addEvent($event1, $callback1);
$loop->addEvent($event2, $callback2);
$loop->run();
eventloop.php Call Stack
main()
EventLoop::create()
new EventLoop()
56
$loop = EventLoop::create();
$loop->addEvent($event1, $callback1);
$loop->addEvent($event2, $callback2);
$loop->run();
eventloop.php Call Stack
main()
EventLoop::create()
new EventLoop()
$this->eventQueue = new SplQueue();
Event
Queue
57
$loop = EventLoop::create();
$loop->addEvent($event1, $callback1);
$loop->addEvent($event2, $callback2);
$loop->run();
eventloop.php Call Stack
main()
EventLoop::create()
new EventLoop()
Event
Queue
58
$loop = EventLoop::create();
$loop->addEvent($event1, $callback1);
$loop->addEvent($event2, $callback2);
$loop->run();
eventloop.php Call Stack
main()
EventLoop::create()
Event
Queue
59
$loop = EventLoop::create();
$loop->addEvent($event1, $callback1);
$loop->addEvent($event2, $callback2);
$loop->run();
eventloop.php Call Stack
main()
Event
Queue
60
$loop = EventLoop::create();
$loop->addEvent($event1, $callback1);
$loop->addEvent($event2, $callback2);
$loop->run();
eventloop.php Call Stack
main()
Event
Queue
61
$loop = EventLoop::create();
$loop->addEvent($event1, $callback1);
$loop->addEvent($event2, $callback2);
$loop->run();
eventloop.php Call Stack
main()
addEvent($event1, $callback1)
Event
Queue
62
$loop = EventLoop::create();
$loop->addEvent($event1, $callback1);
$loop->addEvent($event2, $callback2);
$loop->run();
eventloop.php Call Stack
main()
addEvent($event1, $callback1)
$this->eventQueue->enqueue([
$event1, $callback1
]);
Event
Queue
$event1
63
$loop = EventLoop::create();
$loop->addEvent($event1, $callback1);
$loop->addEvent($event2, $callback2);
$loop->run();
eventloop.php Call Stack
main()
addEvent($event1, $callback1)
Event
Queue
$event1
64
$loop = EventLoop::create();
$loop->addEvent($event1, $callback1);
$loop->addEvent($event2, $callback2);
$loop->run();
eventloop.php Call Stack
main()
Event
Queue
$event1
65
$loop = EventLoop::create();
$loop->addEvent($event1, $callback1);
$loop->addEvent($event2, $callback2);
$loop->run();
eventloop.php Call Stack
main()
Event
Queue
$event1
66
$loop = EventLoop::create();
$loop->addEvent($event1, $callback1);
$loop->addEvent($event2, $callback2);
$loop->run();
eventloop.php Call Stack
main()
addEvent($event2, $callback2)
Event
Queue
$event1
67
$loop = EventLoop::create();
$loop->addEvent($event1, $callback1);
$loop->addEvent($event2, $callback2);
$loop->run();
eventloop.php Call Stack
main()
addEvent($event2, $callback2)
$this->eventQueue->enqueue([
$event2, $callback2
]);
Event
Queue
$event1 $event2
68
$loop = EventLoop::create();
$loop->addEvent($event1, $callback2);
$loop->addEvent($event2, $callback2);
$loop->run();
eventloop.php Call Stack
main()
addEvent($event2, $callback2)
Event
Queue
$event1 $event2
69
$loop = EventLoop::create();
$loop->addEvent($event1, $callback1);
$loop->addEvent($event2, $callback2);
$loop->run();
eventloop.php Call Stack
main()
Event
Queue
$event1 $event2
70
$loop = EventLoop::create();
$loop->addEvent($event1, $callback1);
$loop->addEvent($event2, $callback2);
$loop->run();
eventloop.php Call Stack
main()
Event
Queue
$event1 $event2
71
Call Stack
main()
run()
$loop = EventLoop::create();
$loop->addEvent($event1, $callback1);
$loop->addEvent($event2, $callback2);
$loop->run();
eventloop.php
Event
Queue
$event1 $event2
72
Call Stack
main()
run()
foreach ($this->eventQueue as $event)
$loop = EventLoop::create();
$loop->addEvent($event1, $callback1);
$loop->addEvent($event2, $callback2);
$loop->run();
eventloop.php
echo "Function 1" . PHP_EOL;
return rand(1,10);
$event[0]
Event
Queue
$event2
73
Call Stack
main()
run()
foreach ($this->eventQueue as $event)
$return = $event[0]()
$loop = EventLoop::create();
$loop->addEvent($event1, $callback1);
$loop->addEvent($event2, $callback2);
$loop->run();
eventloop.php
echo "Function 1" . PHP_EOL;
return rand(1,10);
$event[0]
Event
Queue
$event2
74
Call Stack
main()
run()
foreach ($this->eventQueue as $event)
$loop = EventLoop::create();
$loop->addEvent($event1, $callback1);
$loop->addEvent($event2, $callback2);
$loop->run();
eventloop.php
5
$return
Event
Queue
$event2
75
$loop = EventLoop::create();
$loop->addEvent($event1, $callback1);
$loop->addEvent($event2, $callback2);
$loop->run();
eventloop.php Call Stack
main()
run()
foreach ($this->eventQueue as $event)
if (!is_null($event[1]))
5
$return
Event
Queue
$event2
76
$loop = EventLoop::create();
$loop->addEvent($event1, $callback1);
$loop->addEvent($event2, $callback2);
$loop->run();
eventloop.php Call Stack
main()
run()
foreach ($this->eventQueue as $event)
if (!is_null($event[1]))
5
$return
$this->addEvent($wrappedCallback)
Event
Queue
$event2 $callback1
77
$loop = EventLoop::create();
$loop->addEvent($event1, $callback1);
$loop->addEvent($event2, $callback2);
$loop->run();
eventloop.php Call Stack
main()
run()
foreach ($this->eventQueue as $event)
if (!is_null($event[1]))
5
$return
Event
Queue
$event2 $callback1
78
$loop = EventLoop::create();
$loop->addEvent($event1, $callback1);
$loop->addEvent($event2, $callback2);
$loop->run();
eventloop.php Call Stack
main()
run()
foreach ($this->eventQueue as $event)
echo "Function 2". PHP_EOL;
$event[0]
Event
Queue
$callback1
79
$loop = EventLoop::create();
$loop->addEvent($event1, $callback1);
$loop->addEvent($event2, $callback2);
$loop->run();
eventloop.php Call Stack
main()
run()
foreach ($this->eventQueue as $event)
echo "Function 2". PHP_EOL;
$event[0]
Event
Queue
$callback1
$return = $event[0]()
80
$loop = EventLoop::create();
$loop->addEvent($event1, $callback1);
$loop->addEvent($event2, $callback2);
$loop->run();
eventloop.php Call Stack
main()
run()
foreach ($this->eventQueue as $event)
echo "Function 2". PHP_EOL;
$event[0]
Event
Queue
$callback1
$return = $event[0]()
echo
81
$loop = EventLoop::create();
$loop->addEvent($event1, $callback1);
$loop->addEvent($event2, $callback2);
$loop->run();
eventloop.php Call Stack
main()
run()
foreach ($this->eventQueue as $event)
echo "Function 2". PHP_EOL;
$event[0]
Event
Queue
$callback1
$return = $event[0]()
82
$loop = EventLoop::create();
$loop->addEvent($event1, $callback1);
$loop->addEvent($event2, $callback2);
$loop->run();
eventloop.php Call Stack
main()
run()
foreach ($this->eventQueue as $event)
echo "Function 2". PHP_EOL;
$event[0]
Event
Queue
$callback1
$return = $event[0]()
83
$loop = EventLoop::create();
$loop->addEvent($event1, $callback1);
$loop->addEvent($event2, $callback2);
$loop->run();
eventloop.php Call Stack
main()
run()
foreach ($this->eventQueue as $event)
echo "Function 2". PHP_EOL;
$event[0]
Event
Queue
$callback1
$return = $event[0]()
return void
84
$loop = EventLoop::create();
$loop->addEvent($event1, $callback1);
$loop->addEvent($event2, $callback2);
$loop->run();
eventloop.php Call Stack
main()
run()
foreach ($this->eventQueue as $event)
echo "Function 2". PHP_EOL;
$event[0]
Event
Queue
$callback1
$return = $event[0]()
85
$loop = EventLoop::create();
$loop->addEvent($event1, $callback1);
$loop->addEvent($event2, $callback2);
$loop->run();
eventloop.php Call Stack
main()
run()
foreach ($this->eventQueue as $event)
void
$return
Event
Queue
$callback1
if (!is_null($event[1]))
86
$loop = EventLoop::create();
$loop->addEvent($event1, $callback1);
$loop->addEvent($event2, $callback2);
$loop->run();
eventloop.php Call Stack
main()
run()
foreach ($this->eventQueue as $event)
if (!is_null($event[1]))
void
$return
$this->addEvent($wrappedCallback)
Event
Queue
$callback1 $callback2
87
$loop = EventLoop::create();
$loop->addEvent($event1, $callback1);
$loop->addEvent($event2, $callback2);
$loop->run();
eventloop.php Call Stack
main()
run()
foreach ($this->eventQueue as $event)
if (!is_null($event[1]))
void
$return
Event
Queue
$callback1 $callback2
88
$loop = EventLoop::create();
$loop->addEvent($event1, $callback1);
$loop->addEvent($event2, $callback2);
$loop->run();
eventloop.php Call Stack
main()
run()
foreach ($this->eventQueue as $event)
void
$return
Event
Queue
$callback1 $callback2
89
Most Async is
just Event Loop
Programming
It is a different way to structure
your program
90
Most Async is
just Event Loop
Programming
It is a different way to structure
your program
Async is not:
• Concurrent
• Non-Blocking
• Multi-threaded
• Magic
Async can help better structure
your logic
91
Async makes you think about
end results, not order of
operations
92
Async
Concepts
in PHP
93
Event Loops
Adding In The Special Sauce
94
Async Programming
95
Event loop ends
Queue
Empty?
Execute
job
Has
callback?
Add to
queue
Start Event
Loop
Yes
Yes No
No
Async Programming
96
Event loop ends
Queue
Empty?
Execute
job
Has
callback?
Add to
queue
Start Event
Loop
Yes
Yes No
No
Event Loops
ReactPHP
97
98
$loop = Factory::create();
$server = new Server(function (ServerRequestInterface $request) {
return new Response(
200,
array(
'Content-Type' => 'text/plain'
),
"Hello worldn"
);
});
$socket = new ReactSocketServer(
isset($argv[1]) ? $argv[1] : '0.0.0.0:0',
$loop
);
$server->listen($socket);
echo 'Listening on ' . str_replace('tcp:', 'http:', $socket->getAddress()) .
PHP_EOL;
$loop->run();
99
$loop = Factory::create();
$server = new Server(function (ServerRequestInterface $request) {
return new Response(
200,
array(
'Content-Type' => 'text/plain'
),
"Hello worldn"
);
});
$socket = new ReactSocketServer(
isset($argv[1]) ? $argv[1] : '0.0.0.0:0',
$loop
);
$server->listen($socket);
echo 'Listening on ' . str_replace('tcp:', 'http:', $socket->getAddress()) .
PHP_EOL;
$loop->run();
100
$loop = Factory::create();
$server = new Server(function (ServerRequestInterface $request) {
return new Response(
200,
array(
'Content-Type' => 'text/plain'
),
"Hello worldn"
);
});
$socket = new ReactSocketServer(
isset($argv[1]) ? $argv[1] : '0.0.0.0:0',
$loop
);
$server->listen($socket);
echo 'Listening on ' . str_replace('tcp:', 'http:', $socket->getAddress()) .
PHP_EOL;
$loop->run();
101
$loop = Factory::create();
$server = new Server(function (ServerRequestInterface $request) {
return new Response(
200,
array(
'Content-Type' => 'text/plain'
),
"Hello worldn"
);
});
$socket = new ReactSocketServer(
isset($argv[1]) ? $argv[1] : '0.0.0.0:0',
$loop
);
$server->listen($socket);
echo 'Listening on ' . str_replace('tcp:', 'http:', $socket->getAddress()) .
PHP_EOL;
$loop->run();
102
$loop = Factory::create();
$server = new Server(function (ServerRequestInterface $request) {
return new Response(
200,
array(
'Content-Type' => 'text/plain'
),
"Hello worldn"
);
});
$socket = new ReactSocketServer(
isset($argv[1]) ? $argv[1] : '0.0.0.0:0',
$loop
);
$server->listen($socket);
echo 'Listening on ' . str_replace('tcp:', 'http:', $socket->getAddress()) .
PHP_EOL;
$loop->run();
103
$loop = Factory::create();
$server = new Server(function (ServerRequestInterface $request) {
return new Response(
200,
array(
'Content-Type' => 'text/plain'
),
"Hello worldn"
);
});
$socket = new ReactSocketServer(
isset($argv[1]) ? $argv[1] : '0.0.0.0:0',
$loop
);
$server->listen($socket);
echo 'Listening on ' . str_replace('tcp:', 'http:', $socket->getAddress()) .
PHP_EOL;
$loop->run();
104
RatchetPHP
105
$socket = new Socket();
$ws = new WsServer($socket);
$ws->setStrictSubProtocolCheck(false);
$server = new App('localhost', '8080', '0.0.0.0');
$server->routes->add(
'events',
new Route('/events', array('_controller' => new EventsController()))
);
$server->routes->add(
'onAnswer',
new Route('/onAnswer', array('_controller' => new AnswerController()))
);
$server->routes->add(
'socket',
new Route('/socket', array('_controller' => $ws))
);
$server->run();
106
$socket = new Socket();
$ws = new WsServer($socket);
$ws->setStrictSubProtocolCheck(false);
$server = new App('localhost', '8080', '0.0.0.0');
$server->routes->add(
'events',
new Route('/events', array('_controller' => new EventsController()))
);
$server->routes->add(
'onAnswer',
new Route('/onAnswer', array('_controller' => new AnswerController()))
);
$server->routes->add(
'socket',
new Route('/socket', array('_controller' => $ws))
);
$server->run();
107
$socket = new Socket();
$ws = new WsServer($socket);
$ws->setStrictSubProtocolCheck(false);
$server = new App('localhost', '8080', '0.0.0.0');
$server->routes->add(
'events',
new Route('/events', array('_controller' => new EventsController()))
);
$server->routes->add(
'onAnswer',
new Route('/onAnswer', array('_controller' => new AnswerController()))
);
$server->routes->add(
'socket',
new Route('/socket', array('_controller' => $ws))
);
$server->run();
108
$socket = new Socket();
$ws = new WsServer($socket);
$ws->setStrictSubProtocolCheck(false);
$server = new App('localhost', '8080', '0.0.0.0');
$server->routes->add(
'events',
new Route('/events', array('_controller' => new EventsController()))
);
$server->routes->add(
'onAnswer',
new Route('/onAnswer', array('_controller' => new AnswerController()))
);
$server->routes->add(
'socket',
new Route('/socket', array('_controller' => $ws))
);
$server->run();
109
public function onMessage(RatchetConnectionInterface $from, $msg)
{
$event = json_decode($msg, true);
if($event) {
switch($event['event']) {
case 'websocket:dtmf':
try {
$uuid = $this->calls[$from->resourceId];
$talk = $this->nexmo->calls()->get(
new Call($uuid)
)
->talk();
$talk->setText('You pressed ' . $event['digit']);
$talk->put();
break;
} catch (Exception $e) {
var_dump('Error: ' . $e->getMessage());
}
break;
}
} else {
file_put_contents('./sample.wav', $msg, FILE_APPEND | FILE_BINARY);
}
}
110
public function onMessage(RatchetConnectionInterface $from, $msg)
{
$event = json_decode($msg, true);
if($event) {
switch($event['event']) {
case 'websocket:dtmf':
try {
$uuid = $this->calls[$from->resourceId];
$talk = $this->nexmo->calls()->get(
new Call($uuid)
)
->talk();
$talk->setText('You pressed ' . $event['digit']);
$talk->put();
break;
} catch (Exception $e) {
var_dump('Error: ' . $e->getMessage());
}
break;
}
} else {
file_put_contents('./sample.wav', $msg, FILE_APPEND | FILE_BINARY);
}
}
111
public function onMessage(RatchetConnectionInterface $from, $msg)
{
$event = json_decode($msg, true);
if($event) {
switch($event['event']) {
case 'websocket:dtmf':
try {
$uuid = $this->calls[$from->resourceId];
$talk = $this->nexmo->calls()->get(
new Call($uuid)
)
->talk();
$talk->setText('You pressed ' . $event['digit']);
$talk->put();
break;
} catch (Exception $e) {
var_dump('Error: ' . $e->getMessage());
}
break;
}
} else {
file_put_contents('./sample.wav', $msg, FILE_APPEND | FILE_BINARY);
}
}
112
public function onMessage(RatchetConnectionInterface $from, $msg)
{
$event = json_decode($msg, true);
if($event) {
switch($event['event']) {
case 'websocket:dtmf':
try {
$uuid = $this->calls[$from->resourceId];
$talk = $this->nexmo->calls()->get(
new Call($uuid)
)
->talk();
$talk->setText('You pressed ' . $event['digit']);
$talk->put();
break;
} catch (Exception $e) {
var_dump('Error: ' . $e->getMessage());
}
break;
}
} else {
file_put_contents('./sample.wav', $msg, FILE_APPEND | FILE_BINARY);
}
}
113
public function onMessage(RatchetConnectionInterface $from, $msg)
{
$event = json_decode($msg, true);
if($event) {
switch($event['event']) {
case 'websocket:dtmf':
try {
$uuid = $this->calls[$from->resourceId];
$talk = $this->nexmo->calls()->get(
new Call($uuid)
)
->talk();
$talk->setText('You pressed ' . $event['digit']);
$talk->put();
break;
} catch (Exception $e) {
var_dump('Error: ' . $e->getMessage());
}
break;
}
} else {
file_put_contents('./sample.wav', $msg, FILE_APPEND | FILE_BINARY);
}
}
114
public function onMessage(RatchetConnectionInterface $from, $msg)
{
$event = json_decode($msg, true);
if($event) {
switch($event['event']) {
case 'websocket:dtmf':
try {
$uuid = $this->calls[$from->resourceId];
$talk = $this->nexmo->calls()->get(
new Call($uuid)
)
->talk();
$talk->setText('You pressed ' . $event['digit']);
$talk->put();
break;
} catch (Exception $e) {
var_dump('Error: ' . $e->getMessage());
}
break;
}
} else {
file_put_contents('./sample.wav', $msg, FILE_APPEND | FILE_BINARY);
}
}
Promises
Pretty wrappers for callbacks
115
Callback Hell
116
Russian Nesting Doll of Sadness
Callbacks Being Passed To More Callbacks
$activeFloridaUsers = array_filter(
array_filter(
array_filter($users, function($user) {
return $user->accountActive();
}, function($user) {
return $user->getBalance() > 0;
}), function($user) {
return $user->getState() === "FL";
}
));
117
Callbacks Being Passed To More Callbacks
$activeFloridaUsers = array_filter(
array_filter(
array_filter($users, function($user) {
return $user->accountActive();
}, function($user) {
return $user->getBalance() > 0;
}), function($user) {
return $user->getState() === "FL";
}
));
118
Callbacks Being Passed To More Callbacks
$activeFloridaUsers = array_filter(
array_filter(
array_filter($users, function($user) {
return $user->accountActive();
}, function($user) {
return $user->getBalance() > 0;
}), function($user) {
return $user->getState() === "FL";
}
));
119
Callbacks Being Passed To More Callbacks
$activeFloridaUsers = array_filter(
array_filter(
array_filter($users, function($user) {
return $user->accountActive();
}, function($user) {
return $user->getBalance() > 0;
}), function($user) {
return $user->getState() === "FL";
}
));
120
Callbacks Being Passed To More Callbacks
$activeFloridaUsers = array_filter(
array_filter(
array_filter($users, function($user) {
return $user->accountActive();
}), function($user) {
return $user->getBalance() > 0;
}), function($user) {
return $user->getState() === "FL";
}
));
121
Callbacks Being Passed To More Callbacks
$activeFloridaUsers = array_filter(
array_filter(
array_filter($users, function($user) {
return $user->accountActive();
}), function($user) {
return $user->getBalance() > 0;
}), function($user) {
return $user->getState() === "FL";
}
));
122
What do Promises provide?
123
• Built off of Promises/A+
• A cleaner interface for callbacks
• A more structured workflow for one logic block to the next
• A way to handle errors in a clean manner
A Cleaner
Callback
Interface
use GuzzleHttpPromisePromise;
$fulfilled = function ($value) {
echo 'The promise was fulfilled.';
};
$rejected = function ($reason) {
echo 'The promise was rejected.';
};
$promise = new Promise();
$promise->then($fulfilled, $rejected);
$promise->resolve();
124
A Cleaner
Callback
Interface
use GuzzleHttpPromisePromise;
$fulfilled = function ($value) {
echo 'The promise was fulfilled.';
};
$rejected = function ($reason) {
echo 'The promise was rejected.';
};
$promise = new Promise();
$promise->then($fulfilled, $rejected);
$promise->resolve();
125
A Cleaner
Callback
Interface
use GuzzleHttpPromisePromise;
$fulfilled = function ($value) {
echo 'The promise was fulfilled.';
};
$rejected = function ($reason) {
echo 'The promise was rejected.';
};
$promise = new Promise();
$promise->then($fulfilled, $rejected);
$promise->resolve();
126
A Cleaner
Callback
Interface
use GuzzleHttpPromisePromise;
$fulfilled = function ($value) {
echo 'The promise was fulfilled.';
};
$rejected = function ($reason) {
echo 'The promise was rejected.';
};
$promise = new Promise();
$promise->then($fulfilled, $rejected);
$promise->resolve();
127
A Cleaner
Callback
Interface
use GuzzleHttpPromisePromise;
$fulfilled = function ($value) {
echo 'The promise was fulfilled.';
};
$rejected = function ($reason) {
echo 'The promise was rejected.';
};
$promise = new Promise();
$promise->then($fulfilled, $rejected);
$promise->then($fulfilled2, $rejected2);
$promise->resolve();
128
$promise = new Promise();
$promise->then(function ($users) {
return array_filter($users, function($user) {
return $user->accountActive();
});
});
$promise->then(function ($activeUsers) {
return array_filter($activeUsers, function($user) {
return $user->getBalance() > 0;
});
});
$promise->then(function ($usersWithBalance) {
return array_filter($usersWithBalance, function($user) {
return $user->getState() === 'FL';
});
});
129
$promise = new Promise();
$promise->then(function ($users) {
return array_filter($users, function($user) {
return $user->accountActive();
});
});
$promise->then(function ($activeUsers) {
return array_filter($activeUsers, function($user) {
return $user->getBalance() > 0;
});
});
$promise->then(function ($usersWithBalance) {
return array_filter($usersWithBalance, function($user) {
return $user->getState() === 'FL';
});
});
130
$promise = new Promise();
$promise->then(function ($users) {
return array_filter($users, function($user) {
return $user->accountActive();
});
});
$promise->then(function ($activeUsers) {
return array_filter($activeUsers, function($user) {
return $user->getBalance() > 0;
});
});
$promise->then(function ($usersWithBalance) {
return array_filter($usersWithBalance, function($user) {
return $user->getState() === 'FL';
});
});
131
$promise = new Promise();
$promise->then(function ($users) {
return array_filter($users, function($user) {
return $user->accountActive();
});
});
$promise->then(function ($activeUsers) {
return array_filter($activeUsers, function($user) {
return $user->getBalance() > 0;
});
});
$promise->then(function ($usersWithBalance) {
return array_filter($usersWithBalance, function($user) {
return $user->getState() === 'FL';
});
});
132
$promise = new Promise();
$promise->then(function ($users) {
return array_filter($users, function($user) {
return $user->accountActive();
});
});
$promise->then(function ($activeUsers) {
return array_filter($activeUsers, function($user) {
return $user->getBalance() > 0;
});
});
$promise->then(function ($usersWithBalance) {
return array_filter($usersWithBalance, function($user) {
return $user->getState() === 'FL';
});
});
133
$promise->resolve($users);
$activeFLUsers = $promise->wait();
134
Getting the Values
$promise->resolve($users);
$activeFLUsers = $promise->wait();
135
Getting the Values
Additional
Takeaways
136
Worker/Queues
137
Horizontally scale work
VONAGE CONFIDENTIAL
Generators and Coroutines
yielding Control Back to the Event Loop
138
Swoole
Like PHP-FPM but has coroutines
139
140
Chris Tankersley
Senior PHP Developer Advocate
at Nexmo
@dragonmantank
chris@ctankersley.com

More Related Content

PDF
PHP 7 – What changed internally? (Forum PHP 2015)
PPT
An Elephant of a Different Colour: Hack
PDF
R57shell
PPTX
Electrify your code with PHP Generators
PDF
PHP 7 – What changed internally?
PDF
Separation of concerns - DPC12
PDF
Doctrine fixtures
PHP 7 – What changed internally? (Forum PHP 2015)
An Elephant of a Different Colour: Hack
R57shell
Electrify your code with PHP Generators
PHP 7 – What changed internally?
Separation of concerns - DPC12
Doctrine fixtures

What's hot (20)

PDF
Command Bus To Awesome Town
PDF
Models and Service Layers, Hemoglobin and Hobgoblins
KEY
Perl Web Client
KEY
循環参照のはなし
PDF
Design Patterns avec PHP 5.3, Symfony et Pimple
PDF
Nubilus Perl
PPTX
Looping the Loop with SPL Iterators
PDF
Debugging: Rules And Tools - PHPTek 11 Version
PDF
Things I Believe Now That I'm Old
PDF
Xlab #1: Advantages of functional programming in Java 8
PDF
Teaching Your Machine To Find Fraudsters
PDF
PHPCon 2016: PHP7 by Witek Adamus / XSolve
PDF
Database Design Patterns
PDF
The History of PHPersistence
PDF
Introdução ao Perl 6
PDF
PHP tips and tricks
PDF
Crafting Custom Interfaces with Sub::Exporter
PDF
PHP data structures (and the impact of php 7 on them), phpDay Verona 2015, Italy
TXT
PDF
Decoupling with Design Patterns and Symfony2 DIC
Command Bus To Awesome Town
Models and Service Layers, Hemoglobin and Hobgoblins
Perl Web Client
循環参照のはなし
Design Patterns avec PHP 5.3, Symfony et Pimple
Nubilus Perl
Looping the Loop with SPL Iterators
Debugging: Rules And Tools - PHPTek 11 Version
Things I Believe Now That I'm Old
Xlab #1: Advantages of functional programming in Java 8
Teaching Your Machine To Find Fraudsters
PHPCon 2016: PHP7 by Witek Adamus / XSolve
Database Design Patterns
The History of PHPersistence
Introdução ao Perl 6
PHP tips and tricks
Crafting Custom Interfaces with Sub::Exporter
PHP data structures (and the impact of php 7 on them), phpDay Verona 2015, Italy
Decoupling with Design Patterns and Symfony2 DIC
Ad

Similar to You Got Async in my PHP! (20)

ODP
The promise of asynchronous PHP
ODP
The promise of asynchronous php
ODP
The promise of asynchronous PHP
ODP
The promise of asynchronous php
PDF
Build a bot workshop async primer - php[tek]
PDF
Asynchronous PHP and Real-time Messaging
PDF
Meet a parallel, asynchronous PHP world
PDF
ZendCon 2017 - Build a Bot Workshop - Async Primer
PPTX
Cutting Back Processing Time
PDF
From Generator to Fiber the Road to Coroutine in PHP
PDF
2019 11-bgphp
PDF
threads (1).pdfmjlkjfwjgliwiufuaiusyroayr
PDF
Zend con 2016 - Asynchronous Prorgamming in PHP
PDF
Exploring Async PHP (SF Live Berlin 2019)
PDF
php[world] 2016 - You Don’t Need Node.js - Async Programming in PHP
PDF
Php and threads ZTS
PDF
Asynchronous PHP | Codesushi - Warsaw 2017
PPTX
Architecture of web servers
PPTX
Threads and Processes in Operating Systems.pptx
The promise of asynchronous PHP
The promise of asynchronous php
The promise of asynchronous PHP
The promise of asynchronous php
Build a bot workshop async primer - php[tek]
Asynchronous PHP and Real-time Messaging
Meet a parallel, asynchronous PHP world
ZendCon 2017 - Build a Bot Workshop - Async Primer
Cutting Back Processing Time
From Generator to Fiber the Road to Coroutine in PHP
2019 11-bgphp
threads (1).pdfmjlkjfwjgliwiufuaiusyroayr
Zend con 2016 - Asynchronous Prorgamming in PHP
Exploring Async PHP (SF Live Berlin 2019)
php[world] 2016 - You Don’t Need Node.js - Async Programming in PHP
Php and threads ZTS
Asynchronous PHP | Codesushi - Warsaw 2017
Architecture of web servers
Threads and Processes in Operating Systems.pptx
Ad

More from Chris Tankersley (20)

PDF
8 Rules for Better Applications - PHP Tek 2025
PDF
The Art of API Design - PHP Tek 2025, Chris Tankersley
PDF
Docker is Dead: Long Live Containers
PDF
Bend time to your will with git
PDF
Using PHP Functions! (Not those functions, Google Cloud Functions)
PDF
Dead Simple APIs with OpenAPI
PDF
Killer Docker Workflows for Development
ODP
Docker for Developers - PHP Detroit 2018
ODP
Docker for Developers
ODP
They are Watching You
ODP
BASHing at the CLI - Midwest PHP 2018
PDF
You Were Lied To About Optimization
ODP
Docker for PHP Developers - php[world] 2017
ODP
Docker for PHP Developers - Madison PHP 2017
ODP
Docker for Developers - php[tek] 2017
ODP
Why Docker? Dayton PHP, April 2017
PPTX
OOP Is More Then Cars and Dogs - Midwest PHP 2017
PPTX
From Docker to Production - SunshinePHP 2017
PPTX
Docker for Developers - Sunshine PHP
PPTX
Coming to Terms with OOP In Drupal - php[world] 2016
8 Rules for Better Applications - PHP Tek 2025
The Art of API Design - PHP Tek 2025, Chris Tankersley
Docker is Dead: Long Live Containers
Bend time to your will with git
Using PHP Functions! (Not those functions, Google Cloud Functions)
Dead Simple APIs with OpenAPI
Killer Docker Workflows for Development
Docker for Developers - PHP Detroit 2018
Docker for Developers
They are Watching You
BASHing at the CLI - Midwest PHP 2018
You Were Lied To About Optimization
Docker for PHP Developers - php[world] 2017
Docker for PHP Developers - Madison PHP 2017
Docker for Developers - php[tek] 2017
Why Docker? Dayton PHP, April 2017
OOP Is More Then Cars and Dogs - Midwest PHP 2017
From Docker to Production - SunshinePHP 2017
Docker for Developers - Sunshine PHP
Coming to Terms with OOP In Drupal - php[world] 2016

Recently uploaded (20)

PDF
Blue Purple Modern Animated Computer Science Presentation.pdf.pdf
PDF
Dropbox Q2 2025 Financial Results & Investor Presentation
PPTX
MYSQL Presentation for SQL database connectivity
PDF
Network Security Unit 5.pdf for BCA BBA.
PPT
Teaching material agriculture food technology
PDF
The Rise and Fall of 3GPP – Time for a Sabbatical?
PDF
How UI/UX Design Impacts User Retention in Mobile Apps.pdf
DOCX
The AUB Centre for AI in Media Proposal.docx
PDF
Unlocking AI with Model Context Protocol (MCP)
PDF
Encapsulation theory and applications.pdf
PPTX
Digital-Transformation-Roadmap-for-Companies.pptx
PDF
NewMind AI Weekly Chronicles - August'25 Week I
PDF
Architecting across the Boundaries of two Complex Domains - Healthcare & Tech...
PPTX
Detection-First SIEM: Rule Types, Dashboards, and Threat-Informed Strategy
PDF
Electronic commerce courselecture one. Pdf
PDF
Agricultural_Statistics_at_a_Glance_2022_0.pdf
PDF
Diabetes mellitus diagnosis method based random forest with bat algorithm
PDF
Review of recent advances in non-invasive hemoglobin estimation
PPTX
Big Data Technologies - Introduction.pptx
PDF
Machine learning based COVID-19 study performance prediction
Blue Purple Modern Animated Computer Science Presentation.pdf.pdf
Dropbox Q2 2025 Financial Results & Investor Presentation
MYSQL Presentation for SQL database connectivity
Network Security Unit 5.pdf for BCA BBA.
Teaching material agriculture food technology
The Rise and Fall of 3GPP – Time for a Sabbatical?
How UI/UX Design Impacts User Retention in Mobile Apps.pdf
The AUB Centre for AI in Media Proposal.docx
Unlocking AI with Model Context Protocol (MCP)
Encapsulation theory and applications.pdf
Digital-Transformation-Roadmap-for-Companies.pptx
NewMind AI Weekly Chronicles - August'25 Week I
Architecting across the Boundaries of two Complex Domains - Healthcare & Tech...
Detection-First SIEM: Rule Types, Dashboards, and Threat-Informed Strategy
Electronic commerce courselecture one. Pdf
Agricultural_Statistics_at_a_Glance_2022_0.pdf
Diabetes mellitus diagnosis method based random forest with bat algorithm
Review of recent advances in non-invasive hemoglobin estimation
Big Data Technologies - Introduction.pptx
Machine learning based COVID-19 study performance prediction

You Got Async in my PHP!

  • 1. You Got Async in my PHP! PRESENTED BY: Chris Tankersley Senior PHP Developer Advocate @dragonmantank
  • 4. Procedural Programming 4 Do this, then this, then this $t = new Twitter(new HttpClient()); $tweets = $t->getTweets('dragonmantank'); $template = new Template('tweets.php'); echo $template->render([ ‘tweets’ => $tweets, ]);
  • 5. Procedural Programming • Single Threaded • Very susceptible to blocking operations • Easy to write 5 Make Twitter Object Make HTTP Object Get Tweets Read Template Render Template
  • 6. 6 $t = new Twitter(new HttpClient()); $tweets = $t->getTweets('dragonmantank'); $template = new Template('tweets.php'); echo $template->render([ ‘tweets’ => $tweets, ]); script.php Call Stack
  • 7. 7 $t = new Twitter(new HttpClient()); $tweets = $t->getTweets('dragonmantank'); $template = new Template('tweets.php'); echo $template->render([ ‘tweets’ => $tweets, ]); script.php Call Stack main()
  • 8. 8 $t = new Twitter(new HttpClient()); $tweets = $t->getTweets('dragonmantank'); $template = new Template('tweets.php'); echo $template->render([ ‘tweets’ => $tweets, ]); script.php Call Stack main() new HttpClient()
  • 9. 9 $t = new Twitter(new HttpClient()); $tweets = $t->getTweets('dragonmantank'); $template = new Template('tweets.php'); echo $template->render([ ‘tweets’ => $tweets, ]); script.php Call Stack main() new HttpClient() require_once 'src/HttpClient.php'
  • 10. 10 $t = new Twitter(new HttpClient()); $tweets = $t->getTweets('dragonmantank'); $template = new Template('tweets.php'); echo $template->render([ ‘tweets’ => $tweets, ]); script.php Call Stack main() new HttpClient()
  • 11. 11 $t = new Twitter(new HttpClient()); $tweets = $t->getTweets('dragonmantank'); $template = new Template('tweets.php'); echo $template->render([ ‘tweets’ => $tweets, ]); script.php Call Stack main() new Twitter();
  • 12. 12 $t = new Twitter(new HttpClient()); $tweets = $t->getTweets('dragonmantank'); $template = new Template('tweets.php'); echo $template->render([ ‘tweets’ => $tweets, ]); script.php Call Stack main() new Twitter(); require_once 'src/Twitter.php'
  • 13. 13 $t = new Twitter(new HttpClient()); $tweets = $t->getTweets('dragonmantank'); $template = new Template('tweets.php'); echo $template->render([ ‘tweets’ => $tweets, ]); script.php Call Stack main() new Twitter(); require_once 'src/Twitter.php' getenv('TWITTER_KEY')
  • 14. 14 $t = new Twitter(new HttpClient()); $tweets = $t->getTweets('dragonmantank'); $template = new Template('tweets.php'); echo $template->render([ ‘tweets’ => $tweets, ]); script.php Call Stack main() new Twitter(); require_once 'src/Twitter.php'
  • 15. 15 $t = new Twitter(new HttpClient()); $tweets = $t->getTweets('dragonmantank'); $template = new Template('tweets.php'); echo $template->render([ ‘tweets’ => $tweets, ]); script.php Call Stack main() new Twitter(); require_once 'src/Twitter.php' getenv('TWITTER_SECRET')
  • 16. 16 $t = new Twitter(new HttpClient()); $tweets = $t->getTweets('dragonmantank'); $template = new Template('tweets.php'); echo $template->render([ ‘tweets’ => $tweets, ]); script.php Call Stack main() new Twitter(); require_once 'src/Twitter.php'
  • 17. 17 $t = new Twitter(new HttpClient()); $tweets = $t->getTweets('dragonmantank'); $template = new Template('tweets.php'); echo $template->render([ ‘tweets’ => $tweets, ]); script.php Call Stack main() new Twitter();
  • 18. 18 $t = new Twitter(new HttpClient()); $tweets = $t->getTweets('dragonmantank'); $template = new Template('tweets.php'); echo $template->render([ ‘tweets’ => $tweets, ]); script.php Call Stack main()
  • 19. 19 $t = new Twitter(new HttpClient()); $tweets = $t->getTweets('dragonmantank'); $template = new Template('tweets.php'); echo $template->render([ ‘tweets’ => $tweets, ]); script.php Call Stack main() $t->getTweets()
  • 20. 20 $t = new Twitter(new HttpClient()); $tweets = $t->getTweets('dragonmantank'); $template = new Template('tweets.php'); echo $template->render([ ‘tweets’ => $tweets, ]); script.php Call Stack main() $t->getTweets() $httpClient->get($url)
  • 21. 21 $t = new Twitter(new HttpClient()); $tweets = $t->getTweets('dragonmantank'); $template = new Template('tweets.php'); echo $template->render([ ‘tweets’ => $tweets, ]); script.php Call Stack main() $t->getTweets()
  • 22. 22 $t = new Twitter(new HttpClient()); $tweets = $t->getTweets('dragonmantank'); $template = new Template('tweets.php'); echo $template->render([ ‘tweets’ => $tweets, ]); script.php Call Stack main()
  • 23. 23 Wait, how does PHP avoid blocking?
  • 24. 24 Wait, how does PHP avoid blocking? Web Servers, like Apache, are multi-threaded PHP-FPM spins up multiple threads for use
  • 25. Parallel Computing Do this, this, and this at the same time $reports = [ new DailyBalance(), new EndOfDay(), new ProfitLossUpdate(), ]; foreach ($reports as $r) { $pid = pcntl_fork(); if ($pid === 0) { $r->run(); exit(); } } 25
  • 26. Parallel Programming • Multiple Threads • Lets the OS/CPU handle scheduling • Can be tricky to write 26 Make Report Objects Run Daily Balance Report Run End of Day Report Run Profit-Loss Report End
  • 31. 31 Main Thread main() foreach($report) pcntl_fork() Daily Balance Thread main() if ($pid > 0) if ($pid > 0)
  • 33. 33 Main Thread main() foreach($report) Daily Balance Thread main() if ($pid > 0) $r->run()
  • 34. 34 Main Thread main() foreach($report) Daily Balance Thread main() if ($pid > 0) $r->run()pcntl_fork() End Of Day Thread main()
  • 35. 35 Main Thread main() foreach($report) Daily Balance Thread main() if ($pid > 0) $r->run()pcntl_fork() End Of Day Thread main() if ($pid > 0) if ($pid > 0)
  • 36. 36 Main Thread main() foreach($report) Daily Balance Thread main() if ($pid > 0) $r->run()pcntl_fork() End Of Day Thread main() if ($pid > 0) $r->run()
  • 37. 37 Main Thread main() foreach($report) Daily Balance Thread main() if ($pid > 0) $r->run() End Of Day Thread main() if ($pid > 0) $r->run()
  • 38. 38 Main Thread main() foreach($report) Daily Balance Thread main() if ($pid > 0) $r->run() End Of Day Thread main() if ($pid > 0) $r->run()pcntl_fork()
  • 39. 39 Main Thread main() foreach($report) Daily Balance Thread main() if ($pid > 0) $r->run() End Of Day Thread main() if ($pid > 0) $r->run()pcntl_fork() Profit/Loss Thread main()
  • 40. 40 Main Thread main() foreach($report) Daily Balance Thread main() if ($pid > 0) $r->run() End Of Day Thread main() if ($pid > 0) pcntl_fork() Profit/Loss Thread main() if ($pid > 0) if ($pid > 0)
  • 41. 41 Main Thread main() foreach($report) Daily Balance Thread main() if ($pid > 0) $r->run() End Of Day Thread main() pcntl_fork() Profit/Loss Thread main() if ($pid > 0) $r->run()
  • 42. 42 Main Thread main() foreach($report) Daily Balance Thread main() if ($pid > 0) $r->run() Profit/Loss Thread main() if ($pid > 0) $r->run()
  • 43. 43 Main Thread main() Daily Balance Thread main() if ($pid > 0) $r->run() Profit/Loss Thread main() if ($pid > 0) $r->run()
  • 44. 44 Main Thread main() Daily Balance Thread main() if ($pid > 0) $r->run() Profit/Loss Thread main() if ($pid > 0) $r->run() pcntl_wait()
  • 45. 45 Main Thread main() Daily Balance Thread main() if ($pid > 0) $r->run() Profit/Loss Thread main() if ($pid > 0) $r->run() pcntl_wait()
  • 46. 46 Main Thread main() Daily Balance Thread main() if ($pid > 0) $r->run() Profit/Loss Thread main() if ($pid > 0)pcntl_wait()
  • 47. 47 Main Thread main() Daily Balance Thread main() if ($pid > 0) $r->run() Profit/Loss Thread main() pcntl_wait()
  • 48. 48 Main Thread main() Daily Balance Thread main() if ($pid > 0) $r->run() Profit/Loss Thread pcntl_wait()
  • 49. 49 Main Thread main() Daily Balance Thread main() if ($pid > 0) $r->run() pcntl_wait()
  • 50. Async Programming Try and do this, this, and this, as simultaneously as possible $loop = EventLoop::create(); $loop->addEvent(function () { echo "Function 1" . PHP_EOL; return rand(1,10); }, function($num) { echo "Square: " . ($num * $num) . PHP_EOL; }); $loop->addEvent(function () { echo "Function 2". PHP_EOL; }, function() { echo "Function 4" . PHP_EOL; }); $loop->run(); 50
  • 51. Async Programming • Single Threaded • Uses an event loop • Allows quick executions between larger blocking operations 51 Event loop ends Queue Empty? Execute job Has callback? Add to queue Start Event Loop Yes Yes No No
  • 52. 52 $loop = EventLoop::create(); $loop->addEvent($event1, $callback1); $loop->addEvent($event2, $callback2); $loop->run(); eventloop.php Call Stack main()
  • 53. 53 $loop = EventLoop::create(); $loop->addEvent($event1, $callback1); $loop->addEvent($event2, $callback2); $loop->run(); eventloop.php Call Stack main()
  • 54. 54 $loop = EventLoop::create(); $loop->addEvent($event1, $callback1); $loop->addEvent($event2, $callback2); $loop->run(); eventloop.php Call Stack main() EventLoop::create()
  • 55. 55 $loop = EventLoop::create(); $loop->addEvent($event1, $callback1); $loop->addEvent($event2, $callback2); $loop->run(); eventloop.php Call Stack main() EventLoop::create() new EventLoop()
  • 56. 56 $loop = EventLoop::create(); $loop->addEvent($event1, $callback1); $loop->addEvent($event2, $callback2); $loop->run(); eventloop.php Call Stack main() EventLoop::create() new EventLoop() $this->eventQueue = new SplQueue(); Event Queue
  • 57. 57 $loop = EventLoop::create(); $loop->addEvent($event1, $callback1); $loop->addEvent($event2, $callback2); $loop->run(); eventloop.php Call Stack main() EventLoop::create() new EventLoop() Event Queue
  • 58. 58 $loop = EventLoop::create(); $loop->addEvent($event1, $callback1); $loop->addEvent($event2, $callback2); $loop->run(); eventloop.php Call Stack main() EventLoop::create() Event Queue
  • 59. 59 $loop = EventLoop::create(); $loop->addEvent($event1, $callback1); $loop->addEvent($event2, $callback2); $loop->run(); eventloop.php Call Stack main() Event Queue
  • 60. 60 $loop = EventLoop::create(); $loop->addEvent($event1, $callback1); $loop->addEvent($event2, $callback2); $loop->run(); eventloop.php Call Stack main() Event Queue
  • 61. 61 $loop = EventLoop::create(); $loop->addEvent($event1, $callback1); $loop->addEvent($event2, $callback2); $loop->run(); eventloop.php Call Stack main() addEvent($event1, $callback1) Event Queue
  • 62. 62 $loop = EventLoop::create(); $loop->addEvent($event1, $callback1); $loop->addEvent($event2, $callback2); $loop->run(); eventloop.php Call Stack main() addEvent($event1, $callback1) $this->eventQueue->enqueue([ $event1, $callback1 ]); Event Queue $event1
  • 63. 63 $loop = EventLoop::create(); $loop->addEvent($event1, $callback1); $loop->addEvent($event2, $callback2); $loop->run(); eventloop.php Call Stack main() addEvent($event1, $callback1) Event Queue $event1
  • 64. 64 $loop = EventLoop::create(); $loop->addEvent($event1, $callback1); $loop->addEvent($event2, $callback2); $loop->run(); eventloop.php Call Stack main() Event Queue $event1
  • 65. 65 $loop = EventLoop::create(); $loop->addEvent($event1, $callback1); $loop->addEvent($event2, $callback2); $loop->run(); eventloop.php Call Stack main() Event Queue $event1
  • 66. 66 $loop = EventLoop::create(); $loop->addEvent($event1, $callback1); $loop->addEvent($event2, $callback2); $loop->run(); eventloop.php Call Stack main() addEvent($event2, $callback2) Event Queue $event1
  • 67. 67 $loop = EventLoop::create(); $loop->addEvent($event1, $callback1); $loop->addEvent($event2, $callback2); $loop->run(); eventloop.php Call Stack main() addEvent($event2, $callback2) $this->eventQueue->enqueue([ $event2, $callback2 ]); Event Queue $event1 $event2
  • 68. 68 $loop = EventLoop::create(); $loop->addEvent($event1, $callback2); $loop->addEvent($event2, $callback2); $loop->run(); eventloop.php Call Stack main() addEvent($event2, $callback2) Event Queue $event1 $event2
  • 69. 69 $loop = EventLoop::create(); $loop->addEvent($event1, $callback1); $loop->addEvent($event2, $callback2); $loop->run(); eventloop.php Call Stack main() Event Queue $event1 $event2
  • 70. 70 $loop = EventLoop::create(); $loop->addEvent($event1, $callback1); $loop->addEvent($event2, $callback2); $loop->run(); eventloop.php Call Stack main() Event Queue $event1 $event2
  • 71. 71 Call Stack main() run() $loop = EventLoop::create(); $loop->addEvent($event1, $callback1); $loop->addEvent($event2, $callback2); $loop->run(); eventloop.php Event Queue $event1 $event2
  • 72. 72 Call Stack main() run() foreach ($this->eventQueue as $event) $loop = EventLoop::create(); $loop->addEvent($event1, $callback1); $loop->addEvent($event2, $callback2); $loop->run(); eventloop.php echo "Function 1" . PHP_EOL; return rand(1,10); $event[0] Event Queue $event2
  • 73. 73 Call Stack main() run() foreach ($this->eventQueue as $event) $return = $event[0]() $loop = EventLoop::create(); $loop->addEvent($event1, $callback1); $loop->addEvent($event2, $callback2); $loop->run(); eventloop.php echo "Function 1" . PHP_EOL; return rand(1,10); $event[0] Event Queue $event2
  • 74. 74 Call Stack main() run() foreach ($this->eventQueue as $event) $loop = EventLoop::create(); $loop->addEvent($event1, $callback1); $loop->addEvent($event2, $callback2); $loop->run(); eventloop.php 5 $return Event Queue $event2
  • 75. 75 $loop = EventLoop::create(); $loop->addEvent($event1, $callback1); $loop->addEvent($event2, $callback2); $loop->run(); eventloop.php Call Stack main() run() foreach ($this->eventQueue as $event) if (!is_null($event[1])) 5 $return Event Queue $event2
  • 76. 76 $loop = EventLoop::create(); $loop->addEvent($event1, $callback1); $loop->addEvent($event2, $callback2); $loop->run(); eventloop.php Call Stack main() run() foreach ($this->eventQueue as $event) if (!is_null($event[1])) 5 $return $this->addEvent($wrappedCallback) Event Queue $event2 $callback1
  • 77. 77 $loop = EventLoop::create(); $loop->addEvent($event1, $callback1); $loop->addEvent($event2, $callback2); $loop->run(); eventloop.php Call Stack main() run() foreach ($this->eventQueue as $event) if (!is_null($event[1])) 5 $return Event Queue $event2 $callback1
  • 78. 78 $loop = EventLoop::create(); $loop->addEvent($event1, $callback1); $loop->addEvent($event2, $callback2); $loop->run(); eventloop.php Call Stack main() run() foreach ($this->eventQueue as $event) echo "Function 2". PHP_EOL; $event[0] Event Queue $callback1
  • 79. 79 $loop = EventLoop::create(); $loop->addEvent($event1, $callback1); $loop->addEvent($event2, $callback2); $loop->run(); eventloop.php Call Stack main() run() foreach ($this->eventQueue as $event) echo "Function 2". PHP_EOL; $event[0] Event Queue $callback1 $return = $event[0]()
  • 80. 80 $loop = EventLoop::create(); $loop->addEvent($event1, $callback1); $loop->addEvent($event2, $callback2); $loop->run(); eventloop.php Call Stack main() run() foreach ($this->eventQueue as $event) echo "Function 2". PHP_EOL; $event[0] Event Queue $callback1 $return = $event[0]() echo
  • 81. 81 $loop = EventLoop::create(); $loop->addEvent($event1, $callback1); $loop->addEvent($event2, $callback2); $loop->run(); eventloop.php Call Stack main() run() foreach ($this->eventQueue as $event) echo "Function 2". PHP_EOL; $event[0] Event Queue $callback1 $return = $event[0]()
  • 82. 82 $loop = EventLoop::create(); $loop->addEvent($event1, $callback1); $loop->addEvent($event2, $callback2); $loop->run(); eventloop.php Call Stack main() run() foreach ($this->eventQueue as $event) echo "Function 2". PHP_EOL; $event[0] Event Queue $callback1 $return = $event[0]()
  • 83. 83 $loop = EventLoop::create(); $loop->addEvent($event1, $callback1); $loop->addEvent($event2, $callback2); $loop->run(); eventloop.php Call Stack main() run() foreach ($this->eventQueue as $event) echo "Function 2". PHP_EOL; $event[0] Event Queue $callback1 $return = $event[0]() return void
  • 84. 84 $loop = EventLoop::create(); $loop->addEvent($event1, $callback1); $loop->addEvent($event2, $callback2); $loop->run(); eventloop.php Call Stack main() run() foreach ($this->eventQueue as $event) echo "Function 2". PHP_EOL; $event[0] Event Queue $callback1 $return = $event[0]()
  • 85. 85 $loop = EventLoop::create(); $loop->addEvent($event1, $callback1); $loop->addEvent($event2, $callback2); $loop->run(); eventloop.php Call Stack main() run() foreach ($this->eventQueue as $event) void $return Event Queue $callback1 if (!is_null($event[1]))
  • 86. 86 $loop = EventLoop::create(); $loop->addEvent($event1, $callback1); $loop->addEvent($event2, $callback2); $loop->run(); eventloop.php Call Stack main() run() foreach ($this->eventQueue as $event) if (!is_null($event[1])) void $return $this->addEvent($wrappedCallback) Event Queue $callback1 $callback2
  • 87. 87 $loop = EventLoop::create(); $loop->addEvent($event1, $callback1); $loop->addEvent($event2, $callback2); $loop->run(); eventloop.php Call Stack main() run() foreach ($this->eventQueue as $event) if (!is_null($event[1])) void $return Event Queue $callback1 $callback2
  • 88. 88 $loop = EventLoop::create(); $loop->addEvent($event1, $callback1); $loop->addEvent($event2, $callback2); $loop->run(); eventloop.php Call Stack main() run() foreach ($this->eventQueue as $event) void $return Event Queue $callback1 $callback2
  • 89. 89 Most Async is just Event Loop Programming It is a different way to structure your program
  • 90. 90 Most Async is just Event Loop Programming It is a different way to structure your program Async is not: • Concurrent • Non-Blocking • Multi-threaded • Magic
  • 91. Async can help better structure your logic 91
  • 92. Async makes you think about end results, not order of operations 92
  • 94. Event Loops Adding In The Special Sauce 94
  • 95. Async Programming 95 Event loop ends Queue Empty? Execute job Has callback? Add to queue Start Event Loop Yes Yes No No
  • 96. Async Programming 96 Event loop ends Queue Empty? Execute job Has callback? Add to queue Start Event Loop Yes Yes No No Event Loops
  • 98. 98 $loop = Factory::create(); $server = new Server(function (ServerRequestInterface $request) { return new Response( 200, array( 'Content-Type' => 'text/plain' ), "Hello worldn" ); }); $socket = new ReactSocketServer( isset($argv[1]) ? $argv[1] : '0.0.0.0:0', $loop ); $server->listen($socket); echo 'Listening on ' . str_replace('tcp:', 'http:', $socket->getAddress()) . PHP_EOL; $loop->run();
  • 99. 99 $loop = Factory::create(); $server = new Server(function (ServerRequestInterface $request) { return new Response( 200, array( 'Content-Type' => 'text/plain' ), "Hello worldn" ); }); $socket = new ReactSocketServer( isset($argv[1]) ? $argv[1] : '0.0.0.0:0', $loop ); $server->listen($socket); echo 'Listening on ' . str_replace('tcp:', 'http:', $socket->getAddress()) . PHP_EOL; $loop->run();
  • 100. 100 $loop = Factory::create(); $server = new Server(function (ServerRequestInterface $request) { return new Response( 200, array( 'Content-Type' => 'text/plain' ), "Hello worldn" ); }); $socket = new ReactSocketServer( isset($argv[1]) ? $argv[1] : '0.0.0.0:0', $loop ); $server->listen($socket); echo 'Listening on ' . str_replace('tcp:', 'http:', $socket->getAddress()) . PHP_EOL; $loop->run();
  • 101. 101 $loop = Factory::create(); $server = new Server(function (ServerRequestInterface $request) { return new Response( 200, array( 'Content-Type' => 'text/plain' ), "Hello worldn" ); }); $socket = new ReactSocketServer( isset($argv[1]) ? $argv[1] : '0.0.0.0:0', $loop ); $server->listen($socket); echo 'Listening on ' . str_replace('tcp:', 'http:', $socket->getAddress()) . PHP_EOL; $loop->run();
  • 102. 102 $loop = Factory::create(); $server = new Server(function (ServerRequestInterface $request) { return new Response( 200, array( 'Content-Type' => 'text/plain' ), "Hello worldn" ); }); $socket = new ReactSocketServer( isset($argv[1]) ? $argv[1] : '0.0.0.0:0', $loop ); $server->listen($socket); echo 'Listening on ' . str_replace('tcp:', 'http:', $socket->getAddress()) . PHP_EOL; $loop->run();
  • 103. 103 $loop = Factory::create(); $server = new Server(function (ServerRequestInterface $request) { return new Response( 200, array( 'Content-Type' => 'text/plain' ), "Hello worldn" ); }); $socket = new ReactSocketServer( isset($argv[1]) ? $argv[1] : '0.0.0.0:0', $loop ); $server->listen($socket); echo 'Listening on ' . str_replace('tcp:', 'http:', $socket->getAddress()) . PHP_EOL; $loop->run();
  • 105. 105 $socket = new Socket(); $ws = new WsServer($socket); $ws->setStrictSubProtocolCheck(false); $server = new App('localhost', '8080', '0.0.0.0'); $server->routes->add( 'events', new Route('/events', array('_controller' => new EventsController())) ); $server->routes->add( 'onAnswer', new Route('/onAnswer', array('_controller' => new AnswerController())) ); $server->routes->add( 'socket', new Route('/socket', array('_controller' => $ws)) ); $server->run();
  • 106. 106 $socket = new Socket(); $ws = new WsServer($socket); $ws->setStrictSubProtocolCheck(false); $server = new App('localhost', '8080', '0.0.0.0'); $server->routes->add( 'events', new Route('/events', array('_controller' => new EventsController())) ); $server->routes->add( 'onAnswer', new Route('/onAnswer', array('_controller' => new AnswerController())) ); $server->routes->add( 'socket', new Route('/socket', array('_controller' => $ws)) ); $server->run();
  • 107. 107 $socket = new Socket(); $ws = new WsServer($socket); $ws->setStrictSubProtocolCheck(false); $server = new App('localhost', '8080', '0.0.0.0'); $server->routes->add( 'events', new Route('/events', array('_controller' => new EventsController())) ); $server->routes->add( 'onAnswer', new Route('/onAnswer', array('_controller' => new AnswerController())) ); $server->routes->add( 'socket', new Route('/socket', array('_controller' => $ws)) ); $server->run();
  • 108. 108 $socket = new Socket(); $ws = new WsServer($socket); $ws->setStrictSubProtocolCheck(false); $server = new App('localhost', '8080', '0.0.0.0'); $server->routes->add( 'events', new Route('/events', array('_controller' => new EventsController())) ); $server->routes->add( 'onAnswer', new Route('/onAnswer', array('_controller' => new AnswerController())) ); $server->routes->add( 'socket', new Route('/socket', array('_controller' => $ws)) ); $server->run();
  • 109. 109 public function onMessage(RatchetConnectionInterface $from, $msg) { $event = json_decode($msg, true); if($event) { switch($event['event']) { case 'websocket:dtmf': try { $uuid = $this->calls[$from->resourceId]; $talk = $this->nexmo->calls()->get( new Call($uuid) ) ->talk(); $talk->setText('You pressed ' . $event['digit']); $talk->put(); break; } catch (Exception $e) { var_dump('Error: ' . $e->getMessage()); } break; } } else { file_put_contents('./sample.wav', $msg, FILE_APPEND | FILE_BINARY); } }
  • 110. 110 public function onMessage(RatchetConnectionInterface $from, $msg) { $event = json_decode($msg, true); if($event) { switch($event['event']) { case 'websocket:dtmf': try { $uuid = $this->calls[$from->resourceId]; $talk = $this->nexmo->calls()->get( new Call($uuid) ) ->talk(); $talk->setText('You pressed ' . $event['digit']); $talk->put(); break; } catch (Exception $e) { var_dump('Error: ' . $e->getMessage()); } break; } } else { file_put_contents('./sample.wav', $msg, FILE_APPEND | FILE_BINARY); } }
  • 111. 111 public function onMessage(RatchetConnectionInterface $from, $msg) { $event = json_decode($msg, true); if($event) { switch($event['event']) { case 'websocket:dtmf': try { $uuid = $this->calls[$from->resourceId]; $talk = $this->nexmo->calls()->get( new Call($uuid) ) ->talk(); $talk->setText('You pressed ' . $event['digit']); $talk->put(); break; } catch (Exception $e) { var_dump('Error: ' . $e->getMessage()); } break; } } else { file_put_contents('./sample.wav', $msg, FILE_APPEND | FILE_BINARY); } }
  • 112. 112 public function onMessage(RatchetConnectionInterface $from, $msg) { $event = json_decode($msg, true); if($event) { switch($event['event']) { case 'websocket:dtmf': try { $uuid = $this->calls[$from->resourceId]; $talk = $this->nexmo->calls()->get( new Call($uuid) ) ->talk(); $talk->setText('You pressed ' . $event['digit']); $talk->put(); break; } catch (Exception $e) { var_dump('Error: ' . $e->getMessage()); } break; } } else { file_put_contents('./sample.wav', $msg, FILE_APPEND | FILE_BINARY); } }
  • 113. 113 public function onMessage(RatchetConnectionInterface $from, $msg) { $event = json_decode($msg, true); if($event) { switch($event['event']) { case 'websocket:dtmf': try { $uuid = $this->calls[$from->resourceId]; $talk = $this->nexmo->calls()->get( new Call($uuid) ) ->talk(); $talk->setText('You pressed ' . $event['digit']); $talk->put(); break; } catch (Exception $e) { var_dump('Error: ' . $e->getMessage()); } break; } } else { file_put_contents('./sample.wav', $msg, FILE_APPEND | FILE_BINARY); } }
  • 114. 114 public function onMessage(RatchetConnectionInterface $from, $msg) { $event = json_decode($msg, true); if($event) { switch($event['event']) { case 'websocket:dtmf': try { $uuid = $this->calls[$from->resourceId]; $talk = $this->nexmo->calls()->get( new Call($uuid) ) ->talk(); $talk->setText('You pressed ' . $event['digit']); $talk->put(); break; } catch (Exception $e) { var_dump('Error: ' . $e->getMessage()); } break; } } else { file_put_contents('./sample.wav', $msg, FILE_APPEND | FILE_BINARY); } }
  • 117. Callbacks Being Passed To More Callbacks $activeFloridaUsers = array_filter( array_filter( array_filter($users, function($user) { return $user->accountActive(); }, function($user) { return $user->getBalance() > 0; }), function($user) { return $user->getState() === "FL"; } )); 117
  • 118. Callbacks Being Passed To More Callbacks $activeFloridaUsers = array_filter( array_filter( array_filter($users, function($user) { return $user->accountActive(); }, function($user) { return $user->getBalance() > 0; }), function($user) { return $user->getState() === "FL"; } )); 118
  • 119. Callbacks Being Passed To More Callbacks $activeFloridaUsers = array_filter( array_filter( array_filter($users, function($user) { return $user->accountActive(); }, function($user) { return $user->getBalance() > 0; }), function($user) { return $user->getState() === "FL"; } )); 119
  • 120. Callbacks Being Passed To More Callbacks $activeFloridaUsers = array_filter( array_filter( array_filter($users, function($user) { return $user->accountActive(); }, function($user) { return $user->getBalance() > 0; }), function($user) { return $user->getState() === "FL"; } )); 120
  • 121. Callbacks Being Passed To More Callbacks $activeFloridaUsers = array_filter( array_filter( array_filter($users, function($user) { return $user->accountActive(); }), function($user) { return $user->getBalance() > 0; }), function($user) { return $user->getState() === "FL"; } )); 121
  • 122. Callbacks Being Passed To More Callbacks $activeFloridaUsers = array_filter( array_filter( array_filter($users, function($user) { return $user->accountActive(); }), function($user) { return $user->getBalance() > 0; }), function($user) { return $user->getState() === "FL"; } )); 122
  • 123. What do Promises provide? 123 • Built off of Promises/A+ • A cleaner interface for callbacks • A more structured workflow for one logic block to the next • A way to handle errors in a clean manner
  • 124. A Cleaner Callback Interface use GuzzleHttpPromisePromise; $fulfilled = function ($value) { echo 'The promise was fulfilled.'; }; $rejected = function ($reason) { echo 'The promise was rejected.'; }; $promise = new Promise(); $promise->then($fulfilled, $rejected); $promise->resolve(); 124
  • 125. A Cleaner Callback Interface use GuzzleHttpPromisePromise; $fulfilled = function ($value) { echo 'The promise was fulfilled.'; }; $rejected = function ($reason) { echo 'The promise was rejected.'; }; $promise = new Promise(); $promise->then($fulfilled, $rejected); $promise->resolve(); 125
  • 126. A Cleaner Callback Interface use GuzzleHttpPromisePromise; $fulfilled = function ($value) { echo 'The promise was fulfilled.'; }; $rejected = function ($reason) { echo 'The promise was rejected.'; }; $promise = new Promise(); $promise->then($fulfilled, $rejected); $promise->resolve(); 126
  • 127. A Cleaner Callback Interface use GuzzleHttpPromisePromise; $fulfilled = function ($value) { echo 'The promise was fulfilled.'; }; $rejected = function ($reason) { echo 'The promise was rejected.'; }; $promise = new Promise(); $promise->then($fulfilled, $rejected); $promise->resolve(); 127
  • 128. A Cleaner Callback Interface use GuzzleHttpPromisePromise; $fulfilled = function ($value) { echo 'The promise was fulfilled.'; }; $rejected = function ($reason) { echo 'The promise was rejected.'; }; $promise = new Promise(); $promise->then($fulfilled, $rejected); $promise->then($fulfilled2, $rejected2); $promise->resolve(); 128
  • 129. $promise = new Promise(); $promise->then(function ($users) { return array_filter($users, function($user) { return $user->accountActive(); }); }); $promise->then(function ($activeUsers) { return array_filter($activeUsers, function($user) { return $user->getBalance() > 0; }); }); $promise->then(function ($usersWithBalance) { return array_filter($usersWithBalance, function($user) { return $user->getState() === 'FL'; }); }); 129
  • 130. $promise = new Promise(); $promise->then(function ($users) { return array_filter($users, function($user) { return $user->accountActive(); }); }); $promise->then(function ($activeUsers) { return array_filter($activeUsers, function($user) { return $user->getBalance() > 0; }); }); $promise->then(function ($usersWithBalance) { return array_filter($usersWithBalance, function($user) { return $user->getState() === 'FL'; }); }); 130
  • 131. $promise = new Promise(); $promise->then(function ($users) { return array_filter($users, function($user) { return $user->accountActive(); }); }); $promise->then(function ($activeUsers) { return array_filter($activeUsers, function($user) { return $user->getBalance() > 0; }); }); $promise->then(function ($usersWithBalance) { return array_filter($usersWithBalance, function($user) { return $user->getState() === 'FL'; }); }); 131
  • 132. $promise = new Promise(); $promise->then(function ($users) { return array_filter($users, function($user) { return $user->accountActive(); }); }); $promise->then(function ($activeUsers) { return array_filter($activeUsers, function($user) { return $user->getBalance() > 0; }); }); $promise->then(function ($usersWithBalance) { return array_filter($usersWithBalance, function($user) { return $user->getState() === 'FL'; }); }); 132
  • 133. $promise = new Promise(); $promise->then(function ($users) { return array_filter($users, function($user) { return $user->accountActive(); }); }); $promise->then(function ($activeUsers) { return array_filter($activeUsers, function($user) { return $user->getBalance() > 0; }); }); $promise->then(function ($usersWithBalance) { return array_filter($usersWithBalance, function($user) { return $user->getState() === 'FL'; }); }); 133
  • 138. VONAGE CONFIDENTIAL Generators and Coroutines yielding Control Back to the Event Loop 138
  • 139. Swoole Like PHP-FPM but has coroutines 139
  • 140. 140 Chris Tankersley Senior PHP Developer Advocate at Nexmo @dragonmantank chris@ctankersley.com