4. Event-driven, non-blocking I/O with PHP
The ļ¬ow of the application is determined by events.
This might be user interaction, ļ¬le reads, ļ¬le writes,
network events, etc.
Even errors will trigger an event.
5. Event-driven, non-blocking I/O with PHP
The program runs without causing any blocking of
CPU runtime.
This is usually things like reading or writing to a ļ¬le,
communicating with a network resource.
The idea is that any pure CPU interaction will be
many times faster than network requests.
In basic terms, a call to sleep() will block the program
from running.
6. Event-driven, non-blocking I/O with PHP
As in Input/Output.
Meaning that we are dealing with the input and
output of data.
In ReactPHP this is done via streams to prevent
blocking.
Streams can be read from or written to in a linear
fashion and don't need to be consumed in full.
7. Event-driven, non-blocking I/O with PHP
The system is written in pure PHP.
i.e. no third part libraries or other packages are
needed to run ReactPHP.
8. ReactPHP
ā¢ Forget the normal request > action > response
mechanisms that you are familiar with.
ā¢ ReactPHP acts around a central loop and acts more like a
desktop application than a web application.
10. Creating servers?
This is a fully working HTTP server, written using ReactPHP.
<?php
$loop = ReactEventLoopFactory::create();āØ
$server = stream_socket_server('tcp://127.0.0.1:8080');
stream_set_blocking($server, false);
$loop->addReadStream($server, function ($server) use ($loop) {
$conn = stream_socket_accept($server);
$data = "HTTP/1.1 200 OKrnContent-Length: 3rnrnHin";
$loop->addWriteStream($conn, function ($conn) use (&$data, $loop) {
$written = fwrite($conn, $data);
if ($written === strlen($data)) {
fclose($conn);āØ
$loop->removeWriteStream($conn);
} else {āØ
$data = substr($data, $written);
}āØ
});
});āØ
$loop->run();
11. Install Via Composer
ā¢ Include ReactPHP in your composer based project
composer require react/react
ā¢ Once you've included /vendor/autoload.php you should
be ready to go.
require './vendor/autoload.php';
12. ReactPHP
ReactPHP heavily uses the following aspects of PHP
ā¢ Streams
ā¢ Closures
It makes sense to understand what these are.
So let's have a quick look at them.
14. Streams
ā¢ Available since PHP 4.3.0
ā¢ Mostly used transparently in PHP
ā¢ Can be used explicitly
ā¢ Allows you to read and write from ļ¬les or network
endpoints (and more) without blocking
15. Streams
ā¢ Let's say you had a log ļ¬le that was 2gb in size.
ā¢ You could load that into memory using ļ¬le() and the read
the contents.āØ
$contents = file('logfile.log');
ā¢ This would quickly overload your system resources.
16. Streams
ā¢ A better approach is to use streams to open a stream to
the ļ¬le.
ā¢ You can then read through the contents of the ļ¬le without
overloading the system resources.
$handle = fopen('logfile.log', 'r');
while (false !== ($line = fgets($handle))) {
// Do something.
}
ā¢ The fopen() function creates a stream, fgets() reads data
from the stream.
17. Stream Wrappers
ā¢ A few stream wrappers are built into PHP
ā¢ This allows access to data held in diļ¬erent types of
resources
ā¢ We have already seen the ļ¬le:// wrapper in use through
the ļ¬le() function (although you can't use it explicitly).
18. php://input
php://input will read from input.
The following will print out any data sent to the script. Eg
post request data.
$input = fopen('php://input', 'r');āØ
while (false !== ($line = fgets($input))) {
echo $line;
}
19. php://memory
php://memory will create a temporary ļ¬le in memory. You
can then write to and read from that ļ¬le.āØ
// Open memory stream for reading and writing.
$memoryStream = fopen('php://memory', 'rw+');
āØ
// Write to the stream.
$text = 'sometext' . time();
fwrite($memoryStream, $text);āØ
20. http:// & https://
http:// and https:// are standard stream wrappers that allow
streaming of a web resourceāØ
// Open stream to awesome website.āØ
$stream = fopen('https://www.hashbangcode.com/', 'r');
// Read the first 50 bytes.
echo fread($stream, 50);
24. Closures
ā¢ Since PHP 5.3 functions can be generated at runtime
ā¢ This means that functions can be deļ¬ned and assigned to
variables.
ā¢ You might have heard these being called closures or
lambda functions or anonymous functions.
ā¢ There is a little diļ¬erence between them though.
25. Lambda Functions
Lambda functions are essentially anonymous closures that
have no knowledge of their environment.āØ
usort($array, function ($a, $b) {
return $a->property <=> $b->property;
});
This function will not exist outside of the call to usort() and
will be deleted from memory after completion.
26. Lambda Functions
Lambdas can also be assigned to variables.āØ
$closure = function ($name) {
return 'Hello ' . $name . '!';
};
This can now be used anywhere within the same scope.
āØ
echo $closure('Phil');
// prints "Hello Phil!
27. Closures
Closures inherit variables from the parent context via the use
statement.āØ
$day = 'Wednesday';
$closure = function ($name) use ($day) {
return 'Hello ' . $name . '! It is ' . $day . ' today.';
};
echo $closure('Phil');
// Prints "Hello Phil! It is Wednesday."
28. Closures
In reality, the terms lambda and closures are often used
interchangeably.
Many languages swap their names around.
So, donāt worry about the name.
30. The Loop
ā¢ Everything in ReactPHP is centred around an event loop
// Set up the loop.
$loop = ReactEventLoopFactory::create();āØ
// some code that uses the instance āØ
// of the loop event
āØ
// Run the loop.
$loop->run();
31. Periodic Timer
ā¢ The simplest example of the loop in action is with a
periodic timer.
$loop = ReactEventLoopFactory::create();āØ
$counter = 0;āØ
$loop->addPeriodicTimer(1, function() use (&$counter) {
$counter++;āØ
echo "$countern";āØ
});
āØ
$loop->run();
ā¢ This will count up from 0, every second, forever.
32. Read File
ā¢ Another example is to read a ļ¬le.
use ReactStreamReadableResourceStream;āØ
āØ
$loop = ReactEventLoopFactory::create();
āØ
$stream = new ReadableResourceStream(fopen('file.txt', 'r'), $loop);
$stream->on('data', function ($data) {
echo "Read" . $data . PHP_EOL;
});āØ
$stream->on('end', function () {
echo "Finished" . PHP_EOL;āØ
});āØ
$loop->run();
ā¢ This will read a ļ¬le in, print each line and then print, "Finished" when complete.
34. Chat
ā¢ A chat application is a pool of connections (i.e. users) and
a communication stream between them all.
ā¢ When a user enters some text this should be copied to all
other connections in the pool.
35. ConnectionsPool
class ConnectionsPool {āØ
private $connections;
public function __construct() {āØ
$this->connections = new SplObjectStorage();āØ
}
āØ
public function add(ConnectionInterface $connection) {
$connection->write("Welcome to chatn");
āØ
$this->initEvents($connection);āØ
$this->connections->attach($connection);āØ
$this->sendAll("New user enters the chatn", $connection);
echo $this->connections->count() . ' users connected.' . PHP_EOL;
}
}
36. ConnectionsPool
private function initEvents(ConnectionInterface $connection) {
// On receiving the data we loop through other connections
// from the pool and write this data to them
$connection->on('data', function ($data) use ($connection) {āØ
$this->sendAll($data, $connection);āØ
});
// When connection closes detach it from the pool.
$connection->on('close', function () use ($connection) {āØ
$this->connections->detach($connection);āØ
$this->sendAll("A user leaves the chatn", $connection);āØ
echo $this->connections->count() . ' users connected.' .
PHP_EOL;
});
}
37. ConnectionsPool
private function sendAll($data, ConnectionInterface $except){āØ
foreach ($this->connections as $conn) {āØ
if ($conn == $except) {āØ
continue;āØ
}
āØ
$conn->write($data);āØ
}āØ
}
38. ReactPHP
use ReactSocketServer;
$loop = ReactEventLoopFactory::create();āØ
$socket = new Server('0.0.0.0:8080', $loop);
$pool = new ConnectionsPool();
$socket->on('connection', āØ
function (ConnectionInterface $connection) use ($pool) {
$pool->add($connection);
});āØ
echo "Listening on ". $socket->getAddress() . PHP_EOL;āØ
$loop->run();
39. Run the chat server
$ php chat.php
Listening on tcp://0.0.0.0:8080
41. Connect to chat
ā¢ Connecting to the chat server using telnet is ļ¬ne. But itās
also possible to create a chat client using ReactPHP.
42. Conclusion
ā¢ ReactPHP takes a bit of getting your head around.
ā¢ PHP's normal ļ¬ow is "request > action > response" but
that no longer applies here.
ā¢ 'non-blocking' means you can't access ļ¬les, databases
or anything like that without going through a streams.
ā¢ Thankfully a few ReactPHP libraries exist to wrap those
resources and turn them into streams.
43. Resources
ā¢ Oļ¬cial Website : https://reactphp.org/
ā¢ List of third party libraries using ReactPHP: āØ
https://github.com/reactphp/reactphp/wiki/Users
ā¢ Book: Event Driven PHP With React PHP - Sergey Zhuk