PHP Reactive Programming

By Martin Sikora
  • Instant online access to over 7,500+ books and videos
  • Constantly updated with 100+ new titles each month
  • Breadth and depth in over 1,000+ technologies
  1. Introduction to Reactive Programming

About this book

Reactive Programming helps us write code that is concise, clear, and readable. Combining the power of reactive programming and PHP, one of the most widely used languages, will enable you to create web applications more pragmatically.

PHP Reactive Programming will teach you the benefits of reactive programming via real-world examples with a hands-on approach. You will create multiple projects showing RxPHP in action alone and in combination with other libraries.

The book starts with a brief introduction to reactive programming, clearly explaining the importance of building reactive applications. You will use the RxPHP library, built a reddit CLI using it, and also re-implement the Symfony3 Event Dispatcher with RxPHP. You will learn how to test your RxPHP code by writing unit tests. Moving on to more interesting aspects, you will implement a web socket backend by developing a browser game. You will learn to implement quite complex reactive systems while avoiding pitfalls such as circular dependencies by moving the RxJS logic from the frontend to the backend. The book will then focus on writing extendable RxPHP code by developing a code testing tool and also cover Using RxPHP on both the server and client side of the application. With a concluding chapter on reactive programming practices in other languages, this book will serve as a complete guide for you to start writing reactive applications in PHP.

Publication date:
March 2017
Publisher
Packt
Pages
364
ISBN
9781786462879

 

Chapter 1. Introduction to Reactive Programming

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


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 value 7 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


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.

 

Sequential and parallel programming


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.

 

Asynchronous programming


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.

Asynchronous versus parallel programming

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.

 

Functional programming


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(), and zip()

Functional programming in PHP

Let's step aside for a moment and see how the three concepts mentioned above are related to PHP.

Eliminating side effects

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.

Avoiding mutable data

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.

First-class citizens and higher-order functions

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.

Anonymous functions in PHP

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 magic methods

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


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 cells A2 and A3 will be propagated to A1. In programmers' speech, this corresponds to the observer design pattern where A2 and A3 are observables and A1 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.

jQuery Promises

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

Note

In reactive programming, we'll use a very similar approach to Promises, but while a Promise object is always resolved only once (it carries just one value); data streams can generate multiple or even an infinite number of values.

Gulp streaming build system

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.

EventDispatcher component in PHP

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.

 

Reactive Extensions


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.

Autocomplete with RxJS

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:

  1. 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.

  2. Apply the map() function. This is exactly what we have already seen above. Note that this map() function, is in fact, not Array.map(), but Observable.map() instead, because we're not working with arrays here.

  3. Chain with filter() method. Exactly the same case as with map().

  4. 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 every keyup event, but only after at least a 750ms delay between two events.

  5. 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.

  6. 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.

Mouse position on drag and drop

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.

 

Introducing RxPHP


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.

RxPHP 1.x and RxPHP 2

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.

 

Summary


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.

About the Author

  • Martin Sikora

    Martin Sikora has been professionally programming since 2006 for companies such as Miton CZ, Symbio Digital, and PRIA in various languages, mostly PHP and TypeScript. Since 2017, he's freelancing, trying to work on open source projects in TypeScript, PHP, Dart, C, and Python. He's been actively contributing to RxPHP and RxJS 5 on both Github and Stack Overflow. He is a Zend certified engineer and was a member of the winning team during Google Dart Hackathon 2012 in Prague. His first publication was Dart Essentials, by Packt, published in May 2015. Occasionally, Martin writes articles for https://www.smashingmagazine.com/. You can connect with him on LinkedIn at https://www.linkedin.com/in/martin-sikora-a63b9a30/ or GitHub at https://github.com/martinsik.

    Browse publications by this author
Book Title
Unlock this full book FREE 10 day trial
Start Free Trial