This document discusses asynchronous PHP processing and libraries. It begins with an overview of synchronous vs asynchronous processing and blocking vs non-blocking I/O. It then reviews several approaches for asynchronous PHP including Pthreads, pcntl_fork, popen, curl_multi, and event loops with libraries like ReactPHP. ReactPHP is discussed in depth as an event-driven non-blocking I/O library that uses promises and streams for asynchronous operations. Examples are provided for asynchronous HTTP requests, DNS lookups, and a pub/sub application using ZeroMQ. Key points emphasized are that asynchronous code does not necessarily run faster and execution order is not guaranteed.
12. Who am I ?
Wim Godden (@wimgtr)
Founder of Cu.be Solutions (http://cu.be)
Open Source developer since 1997
Developer of PHPCompatibility, OpenX, PHPConsistent, ...
Speaker at Open Source conferences
13. Who are you ?
Developers ?
Ever worked with asynchronous PHP libraries ?
Node.JS ?
22. Pthreads
class WebRequest extends Thread {
public $url;
public $response;
public function __construct($url){
$this->url = $url;
}
public function run() {
$this->response = file_get_contents($this->url);
}
}
$request = new WebRequest("https://cu.be");
if ($request->start()) {
/* do some work here */
$a = array_fill(0, 10000000, 'test');
for ($i = 0; $i < count($a); $i++) {}
/* ensure we have data */
$request->join();
echo $request->response;
}
24. popen
child.php
<?php
/* Do some work */
echo 'Output here';
main.php
<?php
// open child process
$child = popen('php child.php', 'r');
/*
* Do some work, while already doing other
* work in the child process.
*/
// get response from child (if any) as soon at it's ready:
$response = stream_get_contents($child);
W
arning
: doesn't behave
sam
e
on
all operating
system
s
!
28. Libevent, libev, libuv
Event handling libraries
PHP extensions (most through PECL)
libevent = also used by Memcached
libev = not available on Windows
34. Timers – one-time
$ourTimer = $loop->addTimer(
15,
function() {
throw new Exception('We have a timeout somewhere');
}
);
$loop->cancelTimer($ourTimer);
35. Timers - periodic
$aliveTimer = $loop->addPeriodicTimer(
30,
function() use ($host) {
if (isHostAlive($host) === false) {
$loop->cancelTimer($aliveTimer);
throw new Exception('Host ' . $host . ' is dead', HOST_IS_DEAD);
}
}
);
36. ReactPHP – Promises
$deferred = new SomeclassExtendingPromiseDeferred();
$promise = $deferred->promise()
->then(
function ($value) {
// Resolved, use $value
},
function ($reason) {
// Rejected, show or log $reason
},
function ($status) {
// Progress changed, show or log $status
}
);
37. ReactPHP – Chaining then() statements
$promise = $deferred->promise()
->then(
function ($a) {
return $a * 2;
}
)
->then(
function ($b) {
return $b * 2;
}
)
->then(
function ($c) {
echo 'c is now ' . $c;
}
);
$deferred->resolve(1); // Will output 'c is now 4'
38. ReactPHP – Chaining then() statements
$promise = $deferred->promise()
->then(
function ($a) {
if ($a > 5) {
return $a * 2;
} else {
throw new Exception('Too small');
}
}
)
->then(
function ($a) {
echo $a;
},
function ($e) {
echo "We got this exception : " . $e->getMessage();
}
);
$deferred->resolve(10); // Will output 20
$deferred->resolve(1); // Will output : We got this exception : Too small
42. ReactPHP – Promises vs Streams
Promises
→ Very useful
→ But : limited to simple return values
Streams
→ Much more powerful
→ Also somewhat more complex
43. ReactPHP - Streams
Either :
Readable
Writable
Both
Example :
Through stream = filter
Limited only by your imagination !
$loop = ReactEventLoopFactory::create();
$source = new ReactStreamStream(fopen('source.txt', 'r'), $loop);
$filter = new MyLibStreamAlnumFilter();
$dest = new ReactStreamStream(fopen('dest.txt', 'w'), $loop);
$source->pipe($filter)->pipe($dest);
$loop->run();
48. Some golden rules & warnings
Golden rule #1 : asynchronous != faster code
Golden rule #2 : don't assume your code will remain as fast
Golden rule #3 : if you don't need a response, don't wait for one
Warning : async does not guarantee execution order !