Search icon CANCEL
Subscription
0
Cart icon
Your Cart (0 item)
Close icon
You have no products in your basket yet
Arrow left icon
Explore Products
Best Sellers
New Releases
Books
Videos
Audiobooks
Learning Hub
Free Learning
Arrow right icon
PHP Reactive Programming
PHP Reactive Programming

PHP Reactive Programming: Build fault tolerant and high performing application in PHP based on the reactive architecture

eBook
R$80 R$218.99
Paperback
R$272.99
Subscription
Free Trial
Renews at R$50p/m

What do you get with Print?

Product feature icon Instant access to your digital eBook copy whilst your Print order is Shipped
Product feature icon Paperback book shipped to your preferred address
Product feature icon Download this book in EPUB and PDF formats
Product feature icon Access this title in our online reader with advanced features
Product feature icon DRM FREE - Read whenever, wherever and however you want
OR
Modal Close icon
Payment Processing...
tick Completed

Shipping Address

Billing Address

Shipping Methods
Table of content icon View table of contents Preview book icon Preview Book

PHP Reactive Programming

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:

Sequential and parallel programming

In parallel programming, multiple processes can be executed concurrently:

Sequential and parallel programming

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:

Asynchronous programming

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

Left arrow icon Right arrow icon
Download code icon Download Code

Key benefits

  • Develop an interesting multiplayer browser game written in RxJS and re-implement it using RxPHP
  • Enhance existing reactive applications by building a CLI tool combining Symfony Console
  • Implement Gearman and Rabbit MQ for asynchronous communication

Description

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.

Who is this book for?

This book is aimed at people with a solid knowledge of PHP and programming languages in general. We also assume they have at least a little experience with other technologies such as JavaScript, Node.js, and others.

What you will learn

  • How to work with the RxPHP library and see what it offers via many examples
  • Use the RxPHP library in combination with Symfony Console
  • The different approaches to using Symfony3 s Event Dispatcher component
  • Test your reactive PHP code using PHPUnit
  • Analyze PHP source code and apply a custom set of rules by building a CLI tool
Estimated delivery fee Deliver to Brazil

Standard delivery 10 - 13 business days

R$63.95

Premium delivery 3 - 6 business days

R$203.95
(Includes tracking information)

Product Details

Country selected
Publication date, Length, Edition, Language, ISBN-13
Publication date : Mar 24, 2017
Length: 364 pages
Edition : 1st
Language : English
ISBN-13 : 9781786462879
Languages :
Tools :

What do you get with Print?

Product feature icon Instant access to your digital eBook copy whilst your Print order is Shipped
Product feature icon Paperback book shipped to your preferred address
Product feature icon Download this book in EPUB and PDF formats
Product feature icon Access this title in our online reader with advanced features
Product feature icon DRM FREE - Read whenever, wherever and however you want
OR
Modal Close icon
Payment Processing...
tick Completed

Shipping Address

Billing Address

Shipping Methods
Estimated delivery fee Deliver to Brazil

Standard delivery 10 - 13 business days

R$63.95

Premium delivery 3 - 6 business days

R$203.95
(Includes tracking information)

Product Details

Publication date : Mar 24, 2017
Length: 364 pages
Edition : 1st
Language : English
ISBN-13 : 9781786462879
Languages :
Tools :

Packt Subscriptions

See our plans and pricing
Modal Close icon
R$50 billed monthly
Feature tick icon Unlimited access to Packt's library of 7,000+ practical books and videos
Feature tick icon Constantly refreshed with 50+ new titles a month
Feature tick icon Exclusive Early access to books as they're written
Feature tick icon Solve problems while you work with advanced search and reference features
Feature tick icon Offline reading on the mobile app
Feature tick icon Simple pricing, no contract
R$500 billed annually
Feature tick icon Unlimited access to Packt's library of 7,000+ practical books and videos
Feature tick icon Constantly refreshed with 50+ new titles a month
Feature tick icon Exclusive Early access to books as they're written
Feature tick icon Solve problems while you work with advanced search and reference features
Feature tick icon Offline reading on the mobile app
Feature tick icon Choose a DRM-free eBook or Video every month to keep
Feature tick icon PLUS own as many other DRM-free eBooks or Videos as you like for just R$25 each
Feature tick icon Exclusive print discounts
R$800 billed in 18 months
Feature tick icon Unlimited access to Packt's library of 7,000+ practical books and videos
Feature tick icon Constantly refreshed with 50+ new titles a month
Feature tick icon Exclusive Early access to books as they're written
Feature tick icon Solve problems while you work with advanced search and reference features
Feature tick icon Offline reading on the mobile app
Feature tick icon Choose a DRM-free eBook or Video every month to keep
Feature tick icon PLUS own as many other DRM-free eBooks or Videos as you like for just R$25 each
Feature tick icon Exclusive print discounts

Frequently bought together


Stars icon
Total R$ 818.97
PHP 7 Data Structures and Algorithms
R$272.99
PHP Microservices
R$272.99
PHP Reactive Programming
R$272.99
Total R$ 818.97 Stars icon
Banner background image

Table of Contents

10 Chapters
1. Introduction to Reactive Programming Chevron down icon Chevron up icon
2. Reactive Programming with RxPHP Chevron down icon Chevron up icon
3. Writing a Reddit Reader with RxPHP Chevron down icon Chevron up icon
4. Reactive versus a Typical Event-Driven Approach Chevron down icon Chevron up icon
5. Testing RxPHP Code Chevron down icon Chevron up icon
6. PHP Streams API and Higher-Order Observables Chevron down icon Chevron up icon
7. Implementing Socket IPC and WebSocket Server/Client Chevron down icon Chevron up icon
8. Multicasting in RxPHP and PHP7 pthreads Extension Chevron down icon Chevron up icon
9. Multithreaded and Distributed Computing with pthreads and Gearman Chevron down icon Chevron up icon
10. Using Advanced Operators and Techniques in RxPHP Chevron down icon Chevron up icon

Customer reviews

Rating distribution
Full star icon Full star icon Empty star icon Empty star icon Empty star icon 2
(1 Ratings)
5 star 0%
4 star 0%
3 star 0%
2 star 100%
1 star 0%
notgoingtoconsomeoneelse Jun 19, 2017
Full star icon Full star icon Empty star icon Empty star icon Empty star icon 2
Buyer Beware ! Published March 2017 - all examples are for RxPHP 1, when RxPHP 2 is now released ( June 2017) making most of the examples in this book redundant less than 3 months after publish date. Save your money and do not buy this book.
Amazon Verified review Amazon
Get free access to Packt library with over 7500+ books and video courses for 7 days!
Start Free Trial

FAQs

What is the delivery time and cost of print book? Chevron down icon Chevron up icon

Shipping Details

USA:

'

Economy: Delivery to most addresses in the US within 10-15 business days

Premium: Trackable Delivery to most addresses in the US within 3-8 business days

UK:

Economy: Delivery to most addresses in the U.K. within 7-9 business days.
Shipments are not trackable

Premium: Trackable delivery to most addresses in the U.K. within 3-4 business days!
Add one extra business day for deliveries to Northern Ireland and Scottish Highlands and islands

EU:

Premium: Trackable delivery to most EU destinations within 4-9 business days.

Australia:

Economy: Can deliver to P. O. Boxes and private residences.
Trackable service with delivery to addresses in Australia only.
Delivery time ranges from 7-9 business days for VIC and 8-10 business days for Interstate metro
Delivery time is up to 15 business days for remote areas of WA, NT & QLD.

Premium: Delivery to addresses in Australia only
Trackable delivery to most P. O. Boxes and private residences in Australia within 4-5 days based on the distance to a destination following dispatch.

India:

Premium: Delivery to most Indian addresses within 5-6 business days

Rest of the World:

Premium: Countries in the American continent: Trackable delivery to most countries within 4-7 business days

Asia:

Premium: Delivery to most Asian addresses within 5-9 business days

Disclaimer:
All orders received before 5 PM U.K time would start printing from the next business day. So the estimated delivery times start from the next day as well. Orders received after 5 PM U.K time (in our internal systems) on a business day or anytime on the weekend will begin printing the second to next business day. For example, an order placed at 11 AM today will begin printing tomorrow, whereas an order placed at 9 PM tonight will begin printing the day after tomorrow.


Unfortunately, due to several restrictions, we are unable to ship to the following countries:

  1. Afghanistan
  2. American Samoa
  3. Belarus
  4. Brunei Darussalam
  5. Central African Republic
  6. The Democratic Republic of Congo
  7. Eritrea
  8. Guinea-bissau
  9. Iran
  10. Lebanon
  11. Libiya Arab Jamahriya
  12. Somalia
  13. Sudan
  14. Russian Federation
  15. Syrian Arab Republic
  16. Ukraine
  17. Venezuela
What is custom duty/charge? Chevron down icon Chevron up icon

Customs duty are charges levied on goods when they cross international borders. It is a tax that is imposed on imported goods. These duties are charged by special authorities and bodies created by local governments and are meant to protect local industries, economies, and businesses.

Do I have to pay customs charges for the print book order? Chevron down icon Chevron up icon

The orders shipped to the countries that are listed under EU27 will not bear custom charges. They are paid by Packt as part of the order.

List of EU27 countries: www.gov.uk/eu-eea:

A custom duty or localized taxes may be applicable on the shipment and would be charged by the recipient country outside of the EU27 which should be paid by the customer and these duties are not included in the shipping charges been charged on the order.

How do I know my custom duty charges? Chevron down icon Chevron up icon

The amount of duty payable varies greatly depending on the imported goods, the country of origin and several other factors like the total invoice amount or dimensions like weight, and other such criteria applicable in your country.

For example:

  • If you live in Mexico, and the declared value of your ordered items is over $ 50, for you to receive a package, you will have to pay additional import tax of 19% which will be $ 9.50 to the courier service.
  • Whereas if you live in Turkey, and the declared value of your ordered items is over € 22, for you to receive a package, you will have to pay additional import tax of 18% which will be € 3.96 to the courier service.
How can I cancel my order? Chevron down icon Chevron up icon

Cancellation Policy for Published Printed Books:

You can cancel any order within 1 hour of placing the order. Simply contact [email protected] with your order details or payment transaction id. If your order has already started the shipment process, we will do our best to stop it. However, if it is already on the way to you then when you receive it, you can contact us at [email protected] using the returns and refund process.

Please understand that Packt Publishing cannot provide refunds or cancel any order except for the cases described in our Return Policy (i.e. Packt Publishing agrees to replace your printed book because it arrives damaged or material defect in book), Packt Publishing will not accept returns.

What is your returns and refunds policy? Chevron down icon Chevron up icon

Return Policy:

We want you to be happy with your purchase from Packtpub.com. We will not hassle you with returning print books to us. If the print book you receive from us is incorrect, damaged, doesn't work or is unacceptably late, please contact Customer Relations Team on [email protected] with the order number and issue details as explained below:

  1. If you ordered (eBook, Video or Print Book) incorrectly or accidentally, please contact Customer Relations Team on [email protected] within one hour of placing the order and we will replace/refund you the item cost.
  2. Sadly, if your eBook or Video file is faulty or a fault occurs during the eBook or Video being made available to you, i.e. during download then you should contact Customer Relations Team within 14 days of purchase on [email protected] who will be able to resolve this issue for you.
  3. You will have a choice of replacement or refund of the problem items.(damaged, defective or incorrect)
  4. Once Customer Care Team confirms that you will be refunded, you should receive the refund within 10 to 12 working days.
  5. If you are only requesting a refund of one book from a multiple order, then we will refund you the appropriate single item.
  6. Where the items were shipped under a free shipping offer, there will be no shipping costs to refund.

On the off chance your printed book arrives damaged, with book material defect, contact our Customer Relation Team on [email protected] within 14 days of receipt of the book with appropriate evidence of damage and we will work with you to secure a replacement copy, if necessary. Please note that each printed book you order from us is individually made by Packt's professional book-printing partner which is on a print-on-demand basis.

What tax is charged? Chevron down icon Chevron up icon

Currently, no tax is charged on the purchase of any print book (subject to change based on the laws and regulations). A localized VAT fee is charged only to our European and UK customers on eBooks, Video and subscriptions that they buy. GST is charged to Indian customers for eBooks and video purchases.

What payment methods can I use? Chevron down icon Chevron up icon

You can pay with the following card types:

  1. Visa Debit
  2. Visa Credit
  3. MasterCard
  4. PayPal
What is the delivery time and cost of print books? Chevron down icon Chevron up icon

Shipping Details

USA:

'

Economy: Delivery to most addresses in the US within 10-15 business days

Premium: Trackable Delivery to most addresses in the US within 3-8 business days

UK:

Economy: Delivery to most addresses in the U.K. within 7-9 business days.
Shipments are not trackable

Premium: Trackable delivery to most addresses in the U.K. within 3-4 business days!
Add one extra business day for deliveries to Northern Ireland and Scottish Highlands and islands

EU:

Premium: Trackable delivery to most EU destinations within 4-9 business days.

Australia:

Economy: Can deliver to P. O. Boxes and private residences.
Trackable service with delivery to addresses in Australia only.
Delivery time ranges from 7-9 business days for VIC and 8-10 business days for Interstate metro
Delivery time is up to 15 business days for remote areas of WA, NT & QLD.

Premium: Delivery to addresses in Australia only
Trackable delivery to most P. O. Boxes and private residences in Australia within 4-5 days based on the distance to a destination following dispatch.

India:

Premium: Delivery to most Indian addresses within 5-6 business days

Rest of the World:

Premium: Countries in the American continent: Trackable delivery to most countries within 4-7 business days

Asia:

Premium: Delivery to most Asian addresses within 5-9 business days

Disclaimer:
All orders received before 5 PM U.K time would start printing from the next business day. So the estimated delivery times start from the next day as well. Orders received after 5 PM U.K time (in our internal systems) on a business day or anytime on the weekend will begin printing the second to next business day. For example, an order placed at 11 AM today will begin printing tomorrow, whereas an order placed at 9 PM tonight will begin printing the day after tomorrow.


Unfortunately, due to several restrictions, we are unable to ship to the following countries:

  1. Afghanistan
  2. American Samoa
  3. Belarus
  4. Brunei Darussalam
  5. Central African Republic
  6. The Democratic Republic of Congo
  7. Eritrea
  8. Guinea-bissau
  9. Iran
  10. Lebanon
  11. Libiya Arab Jamahriya
  12. Somalia
  13. Sudan
  14. Russian Federation
  15. Syrian Arab Republic
  16. Ukraine
  17. Venezuela