Reactive programming has become a very popular and in demand topic over the last few years, and even though the ideas behind it aren't new, it takes the good parts from multiple different programming paradigms. This book's purpose is to teach you how to start writing PHP applications with principles of reactive programming in mind and in combination with pre-existing libraries.
In this chapter, we'll learn the most important principles that will guide us throughout this entire book:
Recap well-known programming paradigms and quickly explain their meaning for humans.
We'll see how we can use functional PHP programming, even today, using practical examples. We pay special attention to how we can use anonymous functions.
Explain what reactive programing is and what good parts it takes from other programming paradigms.
We'll have a look at some examples of widely spread JavaScript and PHP libraries that already use very similar principles to reactive programming.
Introduce Reactive Extensions and see how these fit into the world of reactive programming.
Show what using Reactive Extensions looks like using RxJS and how it fits into the grand scheme of things.
Create a first simple demo with RxPHP library.
Since reactive programming is a programming paradigm, we'll take a quick look at other common paradigms that all of us have probably already heard of and that you'll see mentioned every time you read or hear about reactive programming.
Imperative programming is a programming paradigm around executing statements that change the program's state.
What this means in human language:
Programming paradigm: This is a set of concepts defining a style of building and structuring programs. Most programming languages, such as PHP, support multiple paradigms. We can also think of it as a mindset and a way we approach problems when using such paradigms.
Statements: Units of action with side effects in imperative programming evaluated in sequences usually containing expressions. Statements are executed for their side effects and expressions for their return value. Consider this example:
$a = 2 + 5
This line of code is a statement where
2 + 5
is an expression. The expected side effect is assigning the value7
to the$a
variable. This leads to changing the program's current state. Another statement could be, for instance:if ($a > 5) { }
This statement has one expression and no return value.
State: Values of program variables in memory at any given time. In imperative programming, we define a series of statements that control the program's flow and, therefore, change its state.
Declarative programming is a paradigm focused on describing a program's logic instead of particular executional steps. In other words, in declarative programming, we define what we want instead of how we want it. In contrast to imperative programming, programs in declarative programming are defined with expressions instead of statements.
Very common examples could be SQL and HTML languages. Consider the following database query:
SELECT * FROM user WHERE id = 42
In SQL, we define what data from what table we want to query, but the implementation details are completely hidden for us. We don't even want to worry about how the database engine stores or indexes the data.
In HTML, we define the structure of elements; what's behind the browser's rendering process isn't important for us. We just want to see the page on the screen.
We can think of sequential and parallel programming as counterparts.
In sequential programming, we're executing processes in order. This means that a process is started when the preceding process has finished. In other words, there is always only one process being executed. The following figure illustrates this principle:

In parallel programming, multiple processes can be executed concurrently:

To make this easier to understand and more relevant to PHP, we can, instead of processes, think of lines of code. PHP interpreter is always sequential and it never executes code in parallel.
In Chapter 9, Multithreaded and Distributed Computing with pthreads and Gearman, we'll use PHP module pthreads that makes it possible to run PHP code in multiple threads, but we'll see that it's not as simple as it seems. Module pthreads, in fact, creates multiple independent PHP interpreters, each running in a separate thread.
The term asynchronous programming is very common in languages such as JavaScript. A very general definition is that, in asynchronous programming, we're executing code in a different order than it was defined. This is typical for any event based application.
For example, in JavaScript, we first define an event listener with its handler, which is executed some time later, when an appropriate event occurs.
In PHP, this could be, for example, a web application that needs to send an e-mail when we create a new blog article. Just, instead of lines of code, we're considering tasks. The following figure demonstrates an asynchronously triggered event:

While the web application was saving an article (processing a task), it triggered an event that sent an e-mail and then carried on with the original task. The event handler had to be defined somewhere before we started this task.
A very common misconception is that asynchronous and parallel programming are the same, or that one is an implication of the other. This is very common in JavaScript where, from the user's perspective, it looks like things are running in parallel.
This isn't true, but many programming languages (in fact, just their interpreters), create the illusion of running in parallel while they're still sequential. They appear to be parallel due to it's event-based nature (JavaScript), or because of their interpreter internals.
For example, Python simulates threads by switching the execution context between different parts of the application. The Python interpreter is still single threaded and executes instructions sequentially, but creates the illusion of running code in parallel.
The functional programming paradigm treats program flow as an evaluation of functions. It utilizes several concepts, where the most important for us are eliminating side effects, avoiding mutable data, functions as first-class citizens and higher-order functions. The output of each function is dependent only on its input argument values, therefore, calling the same function twice has to always return the same value. It's based on declarative programming, in the sense of using expressions instead of statements.
Let's have a deeper look what this means:
Eliminating side effects: While in imperative programming side-effects were desired during program execution, in functional programming it's the exact opposite. Each function is supposed to be an individual building block whose return value is based only on its input values. Note that, in functional programming, it almost never makes sense to define a function that takes no arguments and returns no value. Assuming that functions have no side effects, this means that this function can't do anything (or at least anything observable from the outside). This is in contrast to imperative programming, where using such functions makes sense because they can modify some internal state (of an object for instance). Eliminating side effects leads to more independent and better testable code.
Avoiding mutable data: The concept of not modifying any input values and working with their copies works well with not creating any side effects. Executing the same function with the same input parameters will always return the same value.
First-class citizens and higher-order functions: In programming languages, stating that type/object/function is a first-class citizen (or first-class element) means that this entity supports operations generally available to all other entities. Usually, this includes:
It can be passed as a parameter to functions
It can be returned from a function
It can be assigned to a variable
Higher-order functions have a very similar meaning and have to do at least one of these:
Take a function as an argument
Return a function as a result
In functional programming, this concept of higher-order function is often used in connection with methods on collections such as
map()
,filter()
,reduce()
,concat()
, andzip()
Let's step aside for a moment and see how the three concepts mentioned above are related to PHP.
This is mostly a matter of a good programming style and self-discipline. Of course, PHP doesn't restrict us from violating this rule. Note that, by side effects, we also mean use cases like the following:
function sum($array) { $sum = 0; foreach ($array as $value) { $sum += $value; } saveToDatabase($sum); return $sum; } sum([5, 1, 3, 7, 9]);
Even though we have not defined the function saveToDatabase()
ourselves (for example, it comes from a framework we are using), it's still a side effect. If we execute the same function again, it will return the same value, but the end state is different. For example, it will create the record in the database twice.
This concept is simple with primitive data types, for example:
function add($first, $second) { return $first + $second; } add(5, 2);
However, when working with collections, this principle requires the creation of a new collection and copying values from the old collection to the new one:
function greaterThan($collection, $threshold) { $out = []; foreach ($collection as $val) { if ($val > $threshold) { $out[] = $val; } } return $out; } greaterThan([5, 12, 8, 9, 42], 8); // will return: [12, 9, 42]
The preceding example shows this principle in practice.
In PHP, arrays are passed by reference for performance reasons until the first attempt to modify them. Then the interpreter will create a copy of the original array behind the scene (so called copy-on-write). However, objects are always passed as references, so we'll have to be very careful when working with them.
This concept of immutable collections (or objects in general) became very popular in JavaScript with libraries such as Immutable.js
, made by Facebook (
https://facebook.github.io/immutable-js/
), or the so-called onPush
change detection mechanism in Angular2.
Apart from making our code more predictable, when it's used appropriately, it will simplify checking for changes in large collections because, if any of its items have changed, then the entire collection is replaced by a new instance.
In order to check if two collections contain the same data, we can use the identity operator (===
three equal signs) instead of comparing the collections' items one by one.
In PHP, there are already libraries that make this task easier, for instance, Immutable.php
(
https://github.com/jkoudys/immutable.php
). Also, for example, PHP 5.5+ comes with an immutable version of DateTime
class called DateTimeImmutable
by default.
Now it starts to get interesting. Functions in PHP have been first-class citizens for a very long time already. Moreover, since PHP 5.3+, we can use anonymous functions, which greatly simplifies the usage of higher-order functions.
Consider a very trivial example that applies a function on every item in a collection with the built-in array_map()
function:
$input = ['apple', 'banana', 'orange', 'raspberry']; $lengths = array_map(function($item) { return strlen($item); }, $input); // $lengths = [5, 6, 6, 9];
We have used PHP's array_map()
function to iterate the array and return the length of each string. If we consider just this function call, it uses many of the concepts from multiple paradigms that we have explained above:
array_map(function($item) { return strlen($item); }, $input);
What this means in particular:
Single expression
strlen($item)
and no assignments (declarative programming).Implementation details on how the array is actually iterated are hidden from us (declarative programming).
First-class citizens and higher-order functions (functional programming).
Immutable data - this function call doesn't change the original, but creates a new array (functional programming).
No side effects - everything happens inside the inner closure. If we used any variables, they would exist only inside this closure (functional programming).
Just for comparison, if we wanted to write the same example in imperative programming, it would be just one line longer:
$result = []; foreach ($input as $value) { $result[] = strlen($value); }
Let's take this a little further, and say we want to get the sum of all lengths greater than 5
. First, we'll start with the most obvious imperative approach:
$input = ['apple', 'banana', 'orange', 'raspberry']; $sum = 0; foreach ($input as $fruit) { $length = strlen($fruit); if ($length > 5) { $sum += $length; } } // $sum = 21 printf("sum: %d\n", $sum);
Now, we can write the same thing using functional programming, utilizing three methods we mentioned earlier: map, filter and reduce. In PHP, these are called array_map()
, array_filter()
, and array_reduce()
respectively:
$lengths = array_map(function($fruit) { return strlen($fruit); }, $input); $filtered = array_filter($lengths, function($length) { return $length > 5; }); $sum = array_reduce($filtered, function($a, $b) { return $a + $b; });
We got rid of all statements and used only expressions. The resulting code isn't short, and we had to also create three variables to hold partially processed arrays. So let's transform this into one large nested call:
$sum = array_reduce(array_filter(array_map(function($fruit) { return strlen($fruit); }, $input), function($length) { return $length > 5; }), function($a, $b) { return $a + $b; });
This is a little shorter; we can see the sequence of functions applied and their respective expressions in the same order. We've already encountered inconsistency in function declarations in PHP, as shown in the following code, which has been highly criticized:
array array_map(callable $callback, array $array1 [, $... ]) array array_filter(array $array, callable $callback) mixed array_reduce(array $array, callable $callback)
These are shortened function definitions from PHP documentation. We can see that, sometimes the first argument is the iterated collection; sometimes it's the callback function. The same problem exists with string functions and their haystack-needle arguments. We can try to improve the readability a little with functional-PHP library ( https://github.com/lstrojny/functional-php ) - a collection of functions for functional programming in PHP.
The following code represents the same example as above, but uses lstrojny/functional-php
library:
use function Functional\map; use function Functional\filter; use function Functional\reduce_left; $sum = reduce_left(filter(map($input, function($fruit) { return strlen($fruit); }), function($length) { return $length > 5; }), function($val, $i, $col, $reduction) { return $val + $reduction; });
It definitely looks better, but this is probably the best we can get when using standard PHP arrays.
Let's have a look at how the same problem could be solved in a language where arrays are objects and map, filter and reduce are its methods. Javascript, for example, is such a language, so we can rewrite the same example from above one more time:
var sum = inputs .map(fruit => fruit.length) .filter(len => len > 5) .reduce((a, b) => a + b);
Note
We'll use the new ES6 standard whenever we show any JavaScript code throughout this entire book.
Well, this was quite easy and it meets all our expectations from functional programming much better than PHP. This might be the reason why we almost never use higher-order functions in PHP. They are just too hard to write, read and maintain.
Before we move on, we should look at another topic related to functional programming in PHP that is worth mentioning.
Every anonymous function is internally represented as an instance of a Closure class, shown as follows (we'll also refer to anonymous functions as closures or callables):
$count = function() { printf("%d ", count($this->fruits)); }; var_dump(get_class($count)); // string(7) "Closure"
What's unusual is that we can bind custom $this
object when calling a closure, a concept that is very common in JavaScript but very rarely used in PHP.
Let's define a simple class that we'll use for demonstration:
class MyClass { public $fruits; public function __construct($arr) { $this->fruits = $arr; } }
Then, test the function stored in $count
variable on two objects:
// closures_01.php // ... the class definition goes here $count = function() { printf("%d ", count($this->fruits)); }; $obj1 = new MyClass(['apple', 'banana', 'orange']); $obj2 = new MyClass(['raspberry', 'melon']); $count->call($obj1); $count->call($obj2);
This example prints to console the following output:
$ php closures_01.php 3 2
In PHP, we can specify what variables we want to pass from the parent scope to the closure with the use
keyword. Variables can be also passed by reference, similar to passing variables by reference on function calls. Consider the following example that demonstrates both principles:
// closures_03.php $str = 'Hello, World'; $func = function() use ($str) { $str .= '!!!'; echo $str . "\n"; }; $func(); echo $str . "\n"; $func2 = function() use (&$str) { $str .= '???'; echo $str . "\n"; }; $func2(); echo $str . "\n";
We have two closures $func
and $func2
. The first one works with a copy of $str
so, when we print it outside of the function, it's unmodified. However, the second closure, $func2
works with a reference to the original variable. The output for this demo is as follows:
$ php closures_03.php Hello, World!!! Hello, World Hello, World??? Hello, World???
We'll be passing objects to closures a lot in this book.
There's also a bindTo($newThis)
method with a similar purpose. Instead of evaluating the closure, it returns a new Closure object with $this
binded to $newThis
, which can be later called with for example, call_user_func()
method. When using closures inside objects, the context $this
is bind automatically, so we don't need to worry about it.
Note
Anonymous functions and the Closure class are very well explained in the official documentation, so head over there if you have any hesitations: http://php.net/manual/en/functions.anonymous.php
PHP defines a set of names that can be used as class methods with a special effect. These are all prefixed with two underscores __
. For our purposes, we'll be particularly interested in two of them, called __invoke()
and __call()
.
The __invoke()
method is used when we try to use an object as if it were a regular function. This is useful when we use higher-order functions because we can treat objects and functions exactly the same way.
The second __call()
method is used when we attempt to call an object method that doesn't exist (to be precise, a method that is inaccessible). It receives as arguments the original method name and an array of its arguments that was used when trying to call it.
We'll use both of these magic methods in Chapter 2, Reactive Programming with RxPHP.
The principles shown here aren't very common in PHP, but we'll meet them on several occasions when using functional programming.
Note
Throughout this entire book, we'll try to follow PSR-1 and PSR-2 coding standards (http://www.php-fig.org/psr/). However, we'll often violate them on purpose to keep the source codes as short as possible.
Now, we'll finally grasp reactive programming.
Reactive programming is yet another programming paradigm. It is based around the ability to easily express data flows and the automatic propagation of changes.
Let's explore this in more depth:
Data flows (or data streams): In reactive programming, we want to think about variables as "values that change over time". For example, this could be a mouse position, user click or data coming via WebSockets. Basically, any event-based system can be considered a data stream.
Propagation of change: A very nice example is a spreadsheet editor. If we set the value of a single cell to
A1 = A2 + A3
, this means that every change to cellsA2
andA3
will be propagated toA1
. In programmers' speech, this corresponds to the observer design pattern whereA2
andA3
are observables andA1
is an observer. We'll talk about the observer pattern again later in this chapter.Easily express data flows: This is related mostly to libraries we use rather than to the language itself. It means that, if we want to use reactive programming effectively, we need to be able to manipulate data streams easily. This principle also suggests that reactive programming falls under the category of declarative paradigms.
As we can see, the definition is very broad.
The first part about data flows and propagation of change looks like the observer design pattern with iterables. Expressing data flows with ease could be done with functional programming. This all basically describes what we've already seen in this chapter.
The main differences to the observer pattern are how we think and manipulate with data streams. In previous examples, we always worked with arrays as inputs, which are synchronous, while data streams can be both synchronous and asynchronous. From our point of view, it doesn't matter.
Let's see what a typical implementation of the observer pattern might look like in PHP:
// observer_01.php class Observable { /** @var Observer[] */ private $observers = []; private $id; static private $total = 0; public function __construct() { $this->id = ++self::$total; } public function registerObserver(Observer $observer) { $this->observers[] = $observer; } public function notifyObservers() { foreach ($this->observers as $observer) { $observer->notify($this, func_get_args()); } } public function __toString() { return sprintf('Observable #%d', $this->id); } }
In order to be notified about any changes made by the Observable, we need another class called Observer
that subscribes to an Observable:
// observer_01.php class Observer { static private $total = 0; private $id; public function __construct(Observable $observable) { $this->id = ++self::$total; $observable->registerObserver($this); } public function notify($obsr, $args) { $format = "Observer #%d got "%s" from %s\n"; printf($format, $this->id, implode(', ', $args), $obsr); } }
Then, a typical usage might look like the following:
$observer1 = new Observer($subject); $observer2 = new Observer($subject); $subject->notifyObservers('test');
This example will print two messages to the console:
$ php observer_01.php // Observer #1 got "test" from Observable #1 // Observer #2 got "test" from Observable #1
This almost follows how we defined the reactive programming paradigm. A data stream is a sequence of events coming from an Observable, and changes are propagated to all listening observers. The last point we mentioned above - being able to easily express data flows - isn't really there. What if we wanted to filter out all events that don't match a particular condition, just like we did in the examples with array_filter()
and functional programming? This logic would have to go into each Observer
class implementation.
The principles of reactive programming are actually very common in some libraries. We'll have a look at three of them and see how these relate to what we've just learned about reactive and functional programming.
Probably every web developer has used jQuery at some point. A very handy way of avoiding so-called callback hell is using Promises when dealing with asynchronous calls. For example, calling jQuery.ajax()
returns a Promise
object that is resolved or rejected when the AJAX call has finished:
$.get('/foo/bar').done(response => { // ... }).fail(response => { // ... }).complete(response => { // ... });
A Promise
object represents a value in the future. It's non-blocking (asynchronous), but lets us handle it in a declarative approach.
Another useful use case is chaining callbacks, forming a chain, where each callback can modify the value before propagating it further:
// promises_01.js function functionReturningAPromise() { var d = $.Deferred(); setTimeout(() => d.resolve(42), 0); return d.promise(); } functionReturningAPromise() .then(value => value + 1) .then(value => 'result: ' + value) .then(value => console.log(value));
In this example, we have a single source which is the functionReturningAPromise()
call, and three callbacks where only the last one prints the value that resolved the Promise. We can see that the number 42
was modified twice when going through the chain of callbacks:
$ node promises_01.js result: 43
The Gulp build system has become the most popular build system in JavaScript. It's completely based on streams and manipulating them. Consider the following example:
gulp.src('src/*.js') .pipe(concat('all.min.js')) .pipe(gulp.dest('build'));
This creates a stream of files that match the predicate src/*.js
, concats all of them together and finally writes one single file to build/all.min.js
. Does this remind you of anything?
This is the same declarative and functional approach we used above, when talking about functional programming in PHP. In particular, this concat()
function could be replaced with PHP's array_reduce()
.
Streams in gulp (aka vinyl-source-stream) can be modified in any way we want. We can, for example, split a stream into two new streams:
var filter = require('gulp-filter'); var stream = gulp.src('src/*.js'); var substream1 = stream.pipe(filter(['*.min.js'])); var substream2 = stream.pipe(filter(['!/app/*']));
Or, we can merge two streams and uglify (minify and obfuscate the source code) into one stream:
var merge = require('merge2'); merge(gulp.src('src/*.js'), gulp.src('vendor/*')) .pipe(uglify()); .pipe(gulp.dest('build'));
This stream manipulation corresponds very well to the last concept we used to define the reactive programming paradigm - express data flows with ease - while it's both functional and declarative.
Probably every PHP framework comes with some type of event-driven component to notify various different parts of an application using events.
One such component comes with the Symfony framework out-of-the-box ( https://github.com/symfony/event-dispatcher ). It's an independent component that allows subscribing and listening to events (the observer pattern).
Event listeners can be later grouped by the events they subscribe to and can also be assigned custom tags, as shown in the following code:
use Symfony\Component\EventDispatcher\EventDispatcher; $dispatcher = new EventDispatcher(); $listener = new AcmeListener(); $dispatcher->addListener('event_name', [$listener, 'action']);
This principle is very similar to Zend\EventManager used in Zend Framework. It is just another variation of the Observable - observer combination.
We'll come back to Symfony EventDispatcher
component in
Chapter 4
, Reactive vs a Typical Event-Driven approach, where we'll explore how to apply the reactive programming approach to event-based systems, which should lead to simplification and better-organized code.
Now that we've seen that the principles in the reactive programming paradigm aren't completely new for us, we can start thinking about how to put all this together. In other words, what libraries or frameworks do we really need in order to start writing reactive code.
Reactive Extensions (ReactiveX or just Rx in short) are a set of libraries in various languages that make reactive programming easy even in languages where concepts of asynchronous and functional programming are clumsy, such as PHP. However, there's a very important distinction:
Reactive programming doesn't equal Reactive Extensions.
A Reactive Extension is a library that introduces certain principles as one of the possible ways to approach reactive programming. Very often, when somebody tells you they're using reactive programming to do something in their applications, they're in fact talking about a particular Reactive Extension library in their favorite language.
Reactive Extensions were originally made by Microsoft for .NET and called Rx.NET. Later, it was ported by Netflix to Java as RxJava. Now, there are over a dozen supported languages, the most popular probably being RxJS - the JavaScript implementation.
All ports follow a very similar API design, however, differences occur and we'll talk about them a couple of times. We'll be mostly interested in differences between RxPHP and RxJS.
RxPHP is mostly uncharted territory. A more typical environment where we encounter asynchronous events is JavaScript, so we'll first demonstrate examples in JavaScript (and RxJS 5), and afterwards we will have a look at RxPHP.
Imagine we want to implement an autocomplete feature that downloads suggestions from Wikipedia (this example comes from the official collection of demos on RxJS's GitHub page):
function searchAndReturnPromise(term) { // perform an AJAX request and return a Promise } var keyup = Rx.Observable.fromEvent($('#textInput'), 'keyup') .map(e => e.target.value) .filter(text => text.length > 2) .debounceTime(750) .distinctUntilChanged(); var searcher = keyup.switchMap(searchAndReturnPromise);
Let's take a closer look at how this works:
We create an Observable from the form input's
keyup
event. This function is built into RxJS to simplify creating Observables. We can, of course, create our own Observables as well.Apply the
map()
function. This is exactly what we have already seen above. Note that thismap()
function, is in fact, notArray.map()
, butObservable.map()
instead, because we're not working with arrays here.Chain with
filter()
method. Exactly the same case as withmap()
.Method
debounceTime()
is used to limit propagating an event down the stream only once after a period of time. In this case, we're using 750ms, which means that, when the user starts typing, it won't download data from Wikipedia on everykeyup
event, but only after at least a 750ms delay between two events.The
distinctUntilChanged()
method makes sure we're calling the AJAX request only when the value has really changed from the last time, because it makes no sense to download the same suggestions twice.The last statement with
keyup.switchMap()
guarantees that when making multiple asynchronous calls, only the last one in the stream gets processed. All the others are dismissed. This is important because, when dealing with AJAX calls, we have absolutely no control over which Promise resolves first.
If we didn't use RxJS, this feature would require multiple state variables. At least to keep the last value from the input, the last time the event occurred, and the last request value for the AJAX call. With RxJS, we can focus on what we want to do and not worry about its implementation details (declarative approach).
With Reactive Extensions, this approach fulfills all we described above about reactive programming, functional programming and also, mostly, declarative programming.
Let's have a look at a slightly more complicated example in RxJS. We want to track the relative mouse position from where we start dragging an HTML element, until we release it (mouseup
event).
Pay attention to how this example combines multiple Observables (this example also comes from the official collection of demos on RxJS's GitHub page):
var mouseup = Rx.Observable.fromEvent(dragTarget, 'mouseup'); var mousemove = Rx.Observable.fromEvent(document, 'mousemove'); var mousedown = Rx.Observable.fromEvent(dragTarget, 'mousedown'); var mousedrag = mousedown.mergeMap(md => { var sX = md.offsetX, sY = md.offsetY; return mousemove.map(mm => { mm.preventDefault(); return {left: mm.clientX - sX, top: mm.clientY - sY}; }).takeUntil(mouseup); }); var subscription = mousedrag.subscribe(pos => { dragTarget.style.top = pos.top + 'px'; dragTarget.style.left = pos.left + 'px'; });
Notice that mousedrag
is an Observable created by calling return mousemove(...)
and that it emits events only until a mouseup
event is emitted thanks to takeUntil(mouseup)
.
Normally, without RxJS and with a typical imperative approach, this would be even more complicated than the previous example, with more state variables.
Of course, this requires some basic knowledge of what functions are available for Observables, but even without any previous experience, the code should be reasonably easy to understand. Yet again, the implementation details are completely hidden for us.
RxPHP ( https://github.com/ReactiveX/RxPHP ) is a port of RxJS. We're going to be using Composer to handle all dependencies in our PHP projects. It has become a state of the art tool, so if you haven't used it before, download it first and check out some basic usage at https://getcomposer.org/ .
Then, create a new directory and initialize a composer project:
$ mkdir rxphp_01 $ cd rxphp_01 $ php composer.phar init
Fill in the required fields by the interactive wizard and then add RxPHP as a dependency:
$ php composer.phar require reactivex/rxphp
When the library successfully downloads, composer will also create autoload.php
file to handle all class auto-loading on demand.
Then, our code will print string lengths of different types of fruit:
// rxphp_01.php require __DIR__ . '/vendor/autoload.php'; $fruits = ['apple', 'banana', 'orange', 'raspberry']; $observer = new \Rx\Observer\CallbackObserver( function($value) { printf("%s\n", $value); }, null, function() { print("Complete\n"); }); \Rx\Observable::fromArray($fruits) ->map(function($value) { return strlen($value); }) ->subscribe($observer);
Note
In all future examples, we won't include the autoload.php
file, to keep the examples as short as possible. However, it's obviously required in order to run the examples. If you're unsure, have a look at the source codes provided for each chapter.
We first created an observer - CallbackObserver
to be precise - which takes three functions as arguments. These are called on the next item in the stream, on error and when the input stream is complete and won't emit any more items.
The advantage of the CallbackObserver
class is that we don't need to write a custom observer class every time we want to handle incoming items in some special and not very reusable way. With CallbackObserver
, we can just write the callables for signals we want to handle.
When we run this example, we'll see:
$ php rxphp_01.php 5 6 6 9 Complete
This example was very easy, but compared to the JavaScript environment, it's not very common to use asynchronous operations in PHP and, in case we do have to work asynchronously, it's probably something non-trivial. In Chapter 3, Writing a Reddit reader with RxPHP, we'll use Symfony Console component to handle all user input from the command line and, where we can, use similar principles to handling mouse events as we saw in the two RxJS examples above.
The JavaScript examples work very well as examples of what reactive programming using Reactive Extensions looks like and what its benefits are.
Note
If you want to know more about Reactive Extensions, head over to http://reactivex.io/. Also, before continuing to the next chapter, you can have a look at how many different operators Rx supports http://reactivex.io/documentation/operators.html and how these can be used in different languages.
As of April 2017, there're two versions of RxPHP.
The RxPHP 1.x is stable and requires PHP 5.5+. All examples in this book are made for RxPHP 1.x, more specifically, RxPHP 1.5+. It's API is based mostly on RxJS 4, but it takes some features from RxJS 5 as well.
There's also RxPHP 2 in development, which requires PHP 7.0+. RxPHP 2 API from the user's perspective is almost the same as 1.x, it just makes some things easier (for example working with even loops, as we'll see in Chapter 6, PHP Streams API and Higher-Order Observables). When we encounter any differences worth mentioning, we'll give them extra space.
Note
The newer RxPHP 2 was meant to be based to the PHP loop interoperability specification (https://github.com/async-interop/event-loop). However, the specification is still in pre-release stage and it won't be stable in the nearest future. For this reason, the RxPHP team decided to leave the async-interop support for future releases. For more information visit https://github.com/ReactiveX/RxPHP/pull/150.
In this chapter, we tried to explain the common programming paradigms used in most programming languages. These were: imperative, declarative and functional programming. We also compared the meanings of asynchronous and parallel code.
We spent some time on practical examples of functional programming in PHP and its downsides, and we went through examples of some not very common features, such as the Closure class.
Then, we examined the definition of reactive programming and how it's related to all we saw previously in this chapter.
We introduced Reactive Extensions (Rx) as a library for one of the possible approaches to reactive programming.
In two examples of RxJS, we saw what working with Reactive Extensions looks like in practice and how this matches our definition of reactive programming.
Finally, we introduced RxPHP, which we'll use throughout this entire book. We also quickly talked about differences between RxPHP 1.x and RxPHP 2.
In the next chapter, we'll have a closer look at various parts of the RxPHP library and talk more about the principles used in Reactive Extensions.