From ReactPHP to Facebook Hack's Async implementation and many more, asynchronous programming has been a 'hot' topic lately. But how well does async programming support work in PHP and what can you actually use it for in your projects ? Let's look at some real-world use cases and how they leverage the power of async to do things you didn't know PHP could do.
12. Who am I ?
Wim Godden (@wimgtr)
Founder of Cu.be Solutions (http://cu.be)
Open Source developer since 1997
Developer of OpenX, PHPCompatibility, 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("http://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();
var_dump($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
!
33. Timers – one-time
$ourTimer = $loop->addTimer(
15,
function() {
throw new Exception('We have a timeout somewhere');
}
);
34. 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);
}
}
);
35. ReactPHP – Promises
$deferred = new ReactPromiseDeferred();
$promise = $deferred->promise()
->then(
function ($value) {
// Resolved, use $value
},
function ($reason) {
// Rejected, show or log $reason
},
function ($status) {
// Progress changed, show or log $status
}
);
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
}
);
44. ReactPHP – fetching webpages
$request->on('response',
function($response) use (&$buffer) {
$respones->on('data', function ($data) use (&$buffer) {
$buffer .= $data;
});
}
);
$request->on('end', function() use (&$buffer, $promise) {
$promise->resolve($buffer);
});
$request->end();
$loop->run();
45. ReactPHP – Promises vs Streams
Promises
→ Very useful
→ But : limited to simple return values
Streams
→ Much more powerful
→ Also somewhat more complex
46. 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. PubSub using ZeroMQ
$context = new ReactZMQContext($loop);
$pub = $context->getSocket(ZMQ::SOCKET_PUB);
$pub->connect('tcp://127.0.0.1:5555');
$i = 0;
$loop->addPeriodicTimer(1, function () use (&$i, $pub) {
$i++;
echo "publishing $in";
$pub->sendmulti(array('phptek', 'Message ' .$i));
});
49. PubSub using ZeroMQ
$context = new ReactZMQContext($loop);
$sub = $context->getSocket(ZMQ::SOCKET_SUB);
$sub->bind('tcp://127.0.0.1:5555');
$sub->subscribe('phptek');
$sub->on('message', function ($msg) {
echo "Received: $msgn";
});
50. 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 !