Functional PHP
Functional PHP
Luis Atencio
This book is for sale at http://leanpub.com/functional-php
This is a Leanpub book. Leanpub empowers authors and publishers with the Lean Publishing
process. Lean Publishing is the act of publishing an in-progress ebook using lightweight tools and
many iterations to get reader feedback, pivot until you have the right book and build traction once
you do.
Higher-order PHP . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 16
PHP’s first-class, higher-order functions . . . . . . . . . . . . . . . . . . . . . . . . . . . 16
Using containers improve your APIs . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 21
Closures . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 25
Functional vs Object-Oriented Summary Table . . . . . . . . . . . . . . . . . . . . . . . 28
If you don’t know that PHP also supports writing functional code, then you downloaded the right
book. FP is the programming paradigm you need. While based on very simple concepts, FP requires
a shift in the way you think about a problem. This isn’t a new tool, a library, or an API, but a different
approach to problem solving that will become intuitive once you’ve understood its basic principles,
design patterns, and how they can be used against the most complex tasks. Also, it’s not an all or
nothing solution. In later chapters, I’ll show you how FP can be used in conjunction with OO and
unpack the meaning of “OO in the large, FP in the small.”
Type declarations allow you to qualify any function parameter with its proper class or scalar type
(boolean, integer, string, MyClass, etc). These were partially supported in PHP 5 as “type hints” but
without scalar support. In PHP 7, you can also declare the type of a function’s return value.
Being a dynamic language, PHP will always attempt to coerce values of the wrong type into the
expected scalar type, if appropriate. For instance, a function that expects an integer argument, when
given a string, will coerce that value to an integer:
1 function increment($counter) {
2 return ++$counter;
3 }
4 increment("Ft. Lauderdale"); //-> Ft. Lauderdalf ????
¹http://hacklang.org/
²http://php.net/manual/en/functions.arguments.php#functions.arguments.type-declaration
Thinking Functionally in PHP? 3
Sometimes we want this flexibility, but when we overdo it this can lead to very confusing and hard
to read code. What we’ll do in this book is use PHP’s strict typing mechanism which you can turn
on by including this at the top of every file:
1 declare(strict_types=1);
Type declarations makes your code instantly self-documented, allows the compiler to perform
certain clever optimizations, and lets modern IDEs better guide you using type inference. Types
checks also ensure your code is correct by enforcing type constraints on your function calls. In PHP,
a TypeError occurs when a function contract is violated:
1 increment("Ft. Lauderdale");
2
3 PHP Warning: Uncaught TypeError: Argument 1 passed to increment() must be of th\
4 e type integer, string given...
Armed with the proper tool, let’s discuss why learning to think functionally is important and how
it can help you combat the complexities of PHP programs.
Hello FP
As I mentioned before, functional programming is not a framework or a tool, but a way of writing
code; thinking functionally is radically different from thinking in object-oriented or imperative
terms. So, how do you become functional? How do you begin to think this way? Functional
programming is actually very intuitive once you’ve grasped its essence. Unlearning old habits is
actually the hardest part and can be a huge paradigm shift for most people that come from a different
background.
In simple terms, FP is a software development style that places a major emphasis on the use of
functions. In this regard, you might consider it a procedural programming paradigm (based on
procedures, subroutines, or functions), and at its core it is, but with very different philosophies.
You might say, “well, I already use functions on a day-to-day basis at work; what’s the difference?”
As I mentioned earlier, functional programming requires you to think a bit differently about how to
approach the tasks you are facing. Your goal will be to abstract entire control flows and operations
on data with functions in order to avoid side effects and reduce mutation of state in your application.
By practicing FP, you’ll become an expert in certain PHP language constructs that are rarely used
in other paradigms, like taking advantage of closures and higher-order functions, which were
introduced back in PHP 5.3. Both of these concepts are key to building the functional primitives
that you’ll be using in your code.
Without further ado, let’s start with a simple ‘Hello FP’ example. Creating a simple script is probably
the easiest way to get PHP up and running, and that’s all you’ll need for this chapter. Fire up your
PHP REPL [shell> php -a]. Because I want to focus more on building the theoretical foundations
in this chapter, I’ll use very simple examples and simple functions. As you move through the book,
we’ll tackle on more real-world examples that involve file systems, HTTP requests, databases, etc.
Thinking Functionally in PHP? 4
This program is very simple, but because everything is hard-coded you can’t use it to display
messages dynamically. Say you wanted to change the message contents or where it will be written
to; you will need to rewrite this entire expression. Consider wrapping this code with a function and
making these change-points parameters, so that you write it once and use it with any configuration.
An improvement, indeed, but still not a completely reusable piece of code. Suppose your require-
ments change and now you need to repeat this message twice. Obviously, your reaction will be to
change the business logic of toFile to support this:
This simple thought process of creating parameterized functions to carry out simple tasks is a step
in the right direction; however, it would be nice to minimize reaching into your core logic to support
slight changes in requirements. We need to make our code more extensible. Thinking functionally
involves treating parameters as not just simple scalar values but also as functions themselves that
provide additional functionality; it also involves using functions or (callables) as just pieces of data
that can be passed around anywhere. The end result is that we end up evaluating and combining lots
of functions together that individually don’t add much value, but together solve entire programs.
I’ll make a slight transformation to the function toFile:
Thinking Functionally in PHP? 5
At first, it won’t be intuitive why I made this change. Returning functions from other functions? Let
me fast-forward a bit more and show you how I can use this function in its current form. Here’s a
sneak peek at this same program using a functional approach.
And just as I directed this input text to a file, I could have just as easily sent it to the console, to the
database, or over the network. Without a doubt, this looks radically different than the original. I’ll
highlight just a couple of things now. For starters, the file is not a scalar string anymore; it’s a function
or callable called toFile. Also, notice how I was able to split the logic of IO from manipulating its
contents. Visually, it feels as though we’re creating a bigger function from smaller ones. In traditional
PHP applications, it’s rare to see functions used this way. We typically declare functions and invoke
them directly. In FP, it’s common to pass around function references.
Above all, the important aspect about this code sample above is that it captures the process of
decomposing a program into smaller pieces that are more reusable, reliable, and easier to understand;
then they are combined to form an entire program that is easier to reason about as a whole. Thinking
about each of these simple functions individually is very easy, and separating the concerns of
business logic and file IO makes your programs easier to test. Every functional program follows
this fundamental principle.
Now I just introduced a new concept compose, itself a function, to invoke a series of other functions
together. I’ll explain what this means later on and how to use it to its fullest potential. Behind
the scenes, it basically links each function in a chain-like manner by passing the return value of
one as input to the next. In this case, the string “Functional PHP <i>Rocks!</i>” was passed into
htmlentities which returns an HTML-escaped string, passed into $repeat(2), and finally its result
passed into toFile. All you need to is make sure every function individually executes correctly.
Because PHP 7 ensures that all of the types match, you can be confident this program will yield the
right results. This is analogous to stacking legos together and will be central to the theme in this
book: “The Art of Function Composition.”
So, why does functional code look this way? I like to think of it as basically parameterizing your
code so that you can easily change it in a non-invasive manner—like adjusting an algorithm’s
Thinking Functionally in PHP? 6
initial conditions. This visual quality is not accidental. When comparing the functional to the non-
functional solution, you may have noticed that there is a radical difference in style. Both achieve the
same purpose, yet look very different. This is due to functional programming’s inherent declarative
style of development.
Declarative coding
Functional programming is foremost a declarative programming paradigm. This means they express
a logical connection of operations without revealing how they’re implemented or how data actually
flows through them. Chapter 3 shows you how to build these data flows using point-free coding.
As you know, the more popular models used today in PHP are procedural and object-oriented, both
imperative paradigms. For instance, sites built using older versions of Wordpress or Moodle are
heavily procedural; whereas, sites built using Laravel are completely OOP.
Imperative programming treats a computer program as merely a sequence of top-to-bottom
statements that change the state of the system in order to compute a result. Let’s take a look at a
simple imperative example. Suppose you need to square all of the numbers in an array. An imperative
program follows these steps:
Imperative programming tells the computer, in great detail, how to perform a certain task (looping
through and applying the square formula to each number, in this case). This is the most common
way of writing this code and most likely will be your first approach to tackling this problem.
Declarative programming, on the other hand, separates program description from evaluation. It
focuses on the use of expressions to describe what the logic of a program is or what output would look
like without necessarily specifying its control flow or state changes. Familiar examples of declarative
code are seen in SQL statements:
Also, Regular Expressions. The following code extracts the host name from a URL:
Thinking Functionally in PHP? 7
1 @^(?:http://)?([^/]+)@i
Also, CSS (and alt-CSS like LESS or SASS) files are also declarative:
1 body {
2 background: #f8f6f6;
3 color: #404040;
4 font-family: 'Lucida Grande', Verdana, sans-serif;
5 font-size: 13px;
6 font-weight: normal;
7 line-height: 20px;
8 }
In PHP, declarative code is achieved using higher-order functions that establish a certain vocabulary
based on a few set of primitives like filter, map, reduce, zip, compose, curry, lift, etc. These are just
some of the common terms used a lot with FP that you’ll learn about in this book. Once you employ
this vocabulary to concoct the instructions (subroutines, functions, procedures, etc) that make up
your program, the PHP runtime translates this higher level of abstraction into regular PHP code:
Shifting to a functional approach to tackle this same task, you only need to be concerned with
applying the correct behavior at each element and cede control of looping to other parts of the
system. I can let PHP’s array_map() do the work:
The function array_map() also works with callables or functions just like the compose function
shown earlier. Notice a trend? No? Consider this example. Suppose we also needed to add all of the
values within the array. So, we need add function:
Now, without fiddling with the internals of the function, I use the adder to reduce the array into a
single number:
Comparing this code to the imperative version, you see that you’ve freed yourself from the
responsibility of properly managing a loop counter and array index access; put simply, the more
code you have, the more places there are for bugs to occur. Also, standard loops are not reusable
artifacts, only when they are abstracted within functions. Abstracting loops with functions will
allow you to take advantage of PHP’s anonymous function syntax and closures.
Thinking Functionally in PHP? 8
1. One of the main causes of bugs in software is when the state of an object inadvertently
changes, or its reference becomes null. Immutable objects can be passed around to any
function and their states will always remain the same. You can count on having the peace
mind that state is only permitted to grow but never change. It eases the “cognitive load” (the
amount of state to keep track of in your head) of any single component of your system.
2. Immutable data structures are important in shared memory multithreaded applications. We
won’t talk much about concurrent processing in this book because PHP processes run in
isolation for the most part. Now, whether designing for parallelism or not, stateless objects is a
widely used pattern seen in many common PHP deployments. For example, as a best practice,
Symfony services (or service objects) should always be stateless. A service³ shouldn’t persist
any state and provide a set of transient functions that take in the domain its working on,
perform some kind of computation of business logic, and return the result.
Unfortunately, unlike Scala, F#, and others, PHP provides very poor support for immutable variables.
You’re only options really are using the define function or const keyword. Here’s a quick
comparison of the two:
• const are defined at compile time, which means compilers can be clever about how to store
them, but you can’t conditionally declare them (which is a good thing). The following fails in
PHP 7:
1 if (<some condition>) {
2 const C1 = 'FOO';
3 }
4 else {
5 const C2 = 'BAR';
6 }
• Constants declared with ‘define’ are a bit more versatile and dynamic. Because the compiler
won’t attempt to allocate space for them until it actually sees them. So you can do this:
³https://igor.io/2013/03/31/stateless-services.html
Thinking Functionally in PHP? 9
1 if (<some condition>) {
2 define('C1', 'FOO');
3 }
4 else {
5 define('C2', 'BAR');
6 }
But you should always check if a constant has been defined with defined($name) before accessing
its value using constant($name).
• const properly scopes constants into the namespace you’re class resides in. define will scope
constants globally by default, unless the namespace is explicitly added.
• const behaves like any other variable declaration, which means it’s case sensitive and requires
a valid variable name. Because define is a function, you can use it to create constants with
arbitrary expressions and also declare them to be case insensitive if you wish to do so.
All things considered, const is much better to use because it’s an actual keyword and not just a
function call, which is what constants should be. Perhaps in the future, PHP moves in the direction
of allowing this class-level only feature to be used anywhere to define an entity that can only be
assigned once, whether it be a variable or function:
Of course, as it is now, it’s unrealistic to expect that we declare all of our variables using define. But
you can get close to achieving stateless programs, just like those Symfony services we spoke about
earlier, using pure functions.
• It depends only on the input provided and not on any hidden or external state that may change
during its evaluation or between calls.
• It doesn’t inflict changes beyond its scope, like modifying a global object or a parameter passed
by reference, after its run.
Thinking Functionally in PHP? 10
Intuitively, any function that does not meet these requirements would be qualified as “impure.”
For example, while services are pure objects, repository or Data Access Objects (DAO) aren’t. This
includes your Laravel Active Record objects, for example. Operations in DAOs always cause side
effects because their sole purpose is to interact with an external resource, the database.
Programming with immutability can feel rather strange at first. After all, the whole point of
imperative design, which is what we’re accustomed to, is to declare that variables are to mutate
from one statement to the next (they are “variable” after all). PHP doesn’t make any distinctions
between values (immutable variables) and standard variables–they’re all declared with the same “$”
dollar sign. This is a very natural thing for us to do. Consider the following function that reads and
modifies a global variable:
You can also encounter side effects by accessing instance state through $this:
1 class Counter {
2 private $_counter;
3
4 public function __construct(int $init) {
5 $this->_counter = $init;
6 }
7
8 ...
9
10 public function increment(): int {
11 return ++$this->_counter;
12 }
13 }
Because we don’t have support for immutable variable modifiers, with a bit of discipline, we can still
achieve the same goal. One thing we can do is stop using global variables and the GLOBAL mechanism
Thinking Functionally in PHP? 11
in PHP. This is not only considered bad practice from a functional point of view, but also a bit
frowned upon in modern PHP applications. A function like increment is impure as it reads/modifies
an external variable $counter, which is not local to the function’s scope (it could actually live in a
complete different file).
In addition, in the case of object methods, using $this is automatically accessing the methods’s
external instance scope. While this isn’t nearly as bad as global scope, from a pure FP perspective,
it’s also a side effect.
Generally speaking, functions have side effects when reading from or writing to external resources.
Matters get worse, when this state is shared:
In this case, doWork and doMoreWork are very tightly coupled. This coupling means that you
necessarily need to invoke doWork before calling doMoreWork, always in that order. Hence, you lose
the autonomy of these functions and make them harder to unit test in isolation. Side effects create a
temporal coupling or dependency, which means the execution of one can determine the outcome of
the next. The result of doMoreWork is reliant on doWork. In functional programming, functions should
behave like reusable artifacts that can be evaluated in any order and continue to yield correct results.
Not all side effects are this obvious. Some of them are embedded into language level functions.
Frankly, you should be wary of functions that use parameter references &, such as:
Thinking Functionally in PHP? 12
Instead of returning a new sorted array, it sorts the array in place and returns a (arguably useless)
boolean result:
So, now you need to ask yourself: What practical value would you get from a program that couldn’t
do any of these things? Indeed, pure functions can be very hard to use in a world full of dynamic
behavior and mutation– the real world. But, to benefit from functional programming you don’t
need to avoid all of these; FP just provides a framework to help you manage/reduce side effects by
separating the pure code from the impure. Impure code produces externally visible side effects like
the ones listed above, and in this book you’ll learn ways to deal with this.
For instance, I can easily refactor increment to accept the current counter:
This pure function is now not only immutable but also has a clear contract that describes clearly
the information it needs to carry out its task, making it simpler to understand and use. This is a
simple example, of course, but this level of reasoning can be taken to functions of any complexity.
Generally, the goal is to create functions that do one thing and combine them together instead of
creating large monolithic functions.
Thinking Functionally in PHP? 13
Referential Transparency
We can take the notion of purity a step further. In functional programming, we redefine what it
means to create a function. In a sense we go back to basics, to the maths, and treat functions as
nothing more than a mapping of types. In this case, its input types (arguments) to its output type
(return value). We’ll use a pseudo Haskell notation throughout the book when document a function’s
signature. For example, f :: A -> B is a function f that takes an object of A and returns an object
of type B. So, increment becomes:
Essentially the arrow notation is used to define any callable. A function like toFile, which returns
a function from another function, is defined as:
Functions in mathematics are predictable, constant, and work exactly like this. You can imagine that
A and B are sets that represent the domain and the codomain of a function, respectively. For instance,
the type int is analogous to the set of all integers Z. Functions that return the same values given the
same input always, resembling this mathematical property, are known as referentially transparent
(RT). A RT function can always be directly substituted or replaced for its computed value into any
expression without altering its meaning. In other words, these are all equivalent:
This means that you can use the value 42 in place of any of these expressions. This conclusion can
only be reached when there are no side effects in your code. Using RT functions we derive the
following corollary. Because there are no side effects, a function’s return value is directly derived
from its input. Consequently, void functions A -> () as well as zero-arg functions () -> A will
typically perform side effects.
This makes your code not only easier to test, but also allows you to reason about entire programs
much easier. Referential transparency (also known as equational correctness) is inherited from math,
but functions in programming languages behave nothing like mathematical functions; so achieving
referential transparency is strictly on us, especially in a non-pure functional language such as PHP.
The benefit of doing is is that when your individual functions are predictable, the sum of the parts
is predictable and, hence, much easier to reason about, maintain, and debug, and especially test.
Later on, you’ll learn that functional programs are inherently testable, because referential trans-
parency surfaces another principle of good tests, idempotency. An idempotent unit test is a fancy
term to describe a unit test that’s repeatable and consistent, so that for a given set of input you’re
Thinking Functionally in PHP? 14
guaranteed to compute the same output, always. This “contract” will then be documented as part of
your test code; in essence, you get self-documenting code.
By now you realize why pure functions are the pillar of FP, but we have one more concept to
introduce. If pure functions are the pillars, then composition is the base or the glue that makes up
the entire system.
Purity and referential transparency will encourage you to think this way because in order to
glue simple functions together they must agree on their types of inputs and outputs as well as
arity or number of arguments. You can see how using PHP 7’s strict typing helps in this regard,
because it helps you paint the flow of your program’s execution as it hops from one function to the
next. In short, they must agree on their exposed contracts, which is very similar to the Coding to
Interfaces OO design principle. From referential transparency, we learn that a function’s complexity
is sometimes directly related to the number of arguments it receives. A practical observation and
not a formal concept indicates that the lower the number of function parameters, the simpler the
function tends to be.
Thinking Functionally in PHP? 15
This process is essentially what compose does. Also called a function combinator (for obvious
reasons), compose can glue together functions in a loosely decoupled way by binding one function’s
output to the next one’s input. This is essentially the same coding to interfaces but at a much lower
level of granularity.
Hope you’ve enjoyed this brief introduction of some of the topics covered in this book. In the
next chapters we’ll learn what enables PHP to be used functionally. In particular, you’ll learn
about higher-order, first-class functions, and closures, and some practical examples of using each
technique. This will set the stage for developing data flows in chapter 3. So stay tuned!
Higher-order PHP
I mentioned in chapter 1 that functional programming is not a new framework, library, or design
pattern. Rather, it’s a way of thinking that offers an alternative to the way in which you design
your code. However, paradigms by themselves are just abstract concepts that need the right host
language to become a reality. And, yes! PHP is that language. In this chapter, we’ll take a look at two
important features of PHP that make functional possible: higher-order functions and closures. Both
of these are instrumental in building all of the techniques you’ll learn about in this book. The goal
of this chapter is to teach you how to use functions in a very different way–the functional way.
1 var_dump(function () { });
2
3 //-> class Closure#1 (0) {
4
5 }
If functions behave like objects, it’s logical to think we can assign them to variables.
Assigning to a variable
This means that you should be able to treat a function just like any other type of object. Which
means that they can be assigned to variables. Consider a simple string concatenation function:
⁴http://php.net/manual/en/class.closure.php
Higher-order PHP 17
Behind the scenes this code takes the anonymous function (RHS) and assigns it to the variable
$concat2 (LHS). Alternatively, you can check for the presence of a function variable using is_-
callable()⁵:
1 is_callable($concat2) // 1
As a parameter
Supplying functions as parameters allows you to administer specialized behavior on top of another
function. Suppose I create a simple function that takes a callable and applies it over its other
parameters:
⁵http://php.net/manual/en/function.is-callable.php
Higher-order PHP 18
This function is very explicit in what it’s purpose is, and how I can use it to derive other types of
functions from it. Let’s go over some simple examples:
I mentioned earlier that higher-order functions allow you to supply specialized behavior via function
arguments. Let’s see this in action. What would happen if I call apply($divide)(5, 0)? Correct, a
division by zero error:
To fix this, I’ll create a function called safeDivide that supplies extra null-check logic. This function
is a lot more resilient, returning PHP’s NAN constant back to the caller instead of an exception.
Higher-order PHP 19
The other reason why I prefer this approach is that checking for NAN requires a lot less effort and it’s
much cleaner than having to try and catch exceptions:
1 try {
2 $result = apply($safeDivide)(5, 0);
3 ...
4 return $result;
5 }
6 catch(Exception $e) {
7 Log::error($e->getMessage());
8 }
This approach avoids throwing an exception altogether. Recall from chapter 1 that throwing
exceptions is not only a side effect, as it causes the program stack to unwind and logs written,
but also doesn’t respect the Locality Principle of code. In particular, it fails to obey spatial locality,
which states that related statements that should be executed sequentially shall be placed near each
other. This has more application on CPU architecture, but can also be applied to code design.
Before I leave this topic of passing functions as arguments, it’s important to mention that you may
pass any user-defined function variable as an argument, as well as most native to PHP, but not
the ones that are part of the language such as: echo, print, unset(), isset(), empty(), include,
require, require_once, and others. In these cases, your best bet is to wrap them using your own.
To recap, higher-order functions are possible in PHP because, as of PHP 5.3, they are actually Closure
instances behind the scenes. Before this version, this was just considered an internal design decision,
Higher-order PHP 20
but now you can reliably take advantage of it to approach problems very differently. In this book,
you’ll learn to master higher-order functions.
Furthermore, because functions are true instances, as of PHP 5.4 you can actually invoke methods
on them which gives you more control of an anonymous function after it’s been created (as you
might expect, Closure instances all implement the magic method __invoke(), which is important
for consistency reasons with other classes).
1 class Counter {
2 private $_value;
3
4 public function __construct($init) {
5 $this->_value = $init;
6 }
7
8 public function increment(): int {
9 return $this->_value++;
10 }
11 }
12
13 $c = new Counter(0);
14 $c->increment(); //-> 1
15 $c->increment(); //-> 2
16 $c->increment(); //-> 3
The increment function is theoretically considered not pure (or impure) because it’s reaching for
data in its outer scope (the instance scope). Fortunately, this class encapsulates this state pretty well
and doesn’t expose any mutation methods as in the form of a setter. So, from a practical standpoint,
this object is predictable and constant. We can go ahead and make this object invocable by adding
the magic __invoke() method to it:
Higher-order PHP 21
In practical functional programming, there are many design patterns that revolve around wrapping
values into objects and using functions to manipulate them. But for the most part, we’ll prefer to
separate the behavior from the state. One way of doing this to keep things semantically meaningful
is to prefer static functions that declare arguments for any data they need to carry out their job:
1 class Counter {
2 ...
3 public static function increment(int $val): int {
4 return $val + 1;
5 }
6 }
7
8 Counter::increment(100); //-> 101
1 class Container {
2 private $_value;
3
4 private function __construct($value) {
5 $this->_value = $value;
6 }
7
8 // Unit function
9 public static function of($val) {
10 return new static($val);
11 }
12
13 // Map function
14 public function map(callable $f) {
15 return static::of(call_user_func($f, $this->_value));
16 }
17
18 // Print out the container
19 public function __toString(): string {
20 return "Container[ {$this->_value} ]";
21 }
22
23 // Deference container
24 public function __invoke() {
25 return $this->_value;
26 }
27 }
Containers wrap data and provide a mechanism to transform it in a controlled manner via a mapping
function. This is in many ways analogous to the way you can map functions over an array using
array_map():
I can call it with container_map, or I can use it directly. For instance, I can apply a series of
transformations on a string fluently like this:
Higher-order PHP 23
Notice how this looks much cleaner and easier to parse against nesting these function calls one inside
the other. Personally, I rather see code in a flattened out and linear model than something like:
I also added some PHP magic with __invoke() that can be used to dereference the container upon
invocation as such:
1 $c = Container::of('Hello FP')->map($repeat(2))->map(strlen);
2 $c(); //-> 16
So, what’s the use for this pattern? Earlier I mentioned that throwing exceptions, or for that matter,
the imperative try/catch mechanism has side effects. Let’s circle back to that for a moment.
Arguably, try/catch is also not very declarative and belongs in the same category as for loops and
conditional statements. Containerizing values is an important design pattern in FP because it allows
you to consolidate the logic of applying a function chain (sequence) of transformations to some
value immutably and side effect free; it’s immutable because it’s always returning new instances of
the container.
This can be used to implement error handling. Consider this scenario:
1 $c = Container::of([1,2,3])->map(array_reverse);
2 print_r($c()) //-> [3, 2, 1]
But if instead of a valid array, a null value was passed in, you will see:
One way to get around this is to make sure all functions you use (PHP or your own) are “safe,” or
do some level of null-checking. Consider the implementation for a SafeContainer:
Higher-order PHP 24
With this I don’t have to worry about the error checking to clutter all of my business logic; it’s all
consolidated in one place. Let’s see it in action:
1 $c = SafeContainer::of(null)->map(array_reverse);
2 print_r($c()); //-> Container[null]
The best part about this is that your function chains look exactly the same, there’s nothing extra
on your part, so you can continue to map as many functions as you need and any errors will be
propagated through the entire chain behind the scenes.
Now let’s mix it up and use containers with higher-order functions. Here’s an example:
Just for completeness sake, here’s a container called SafeNumber to tackle our division-by-zero
problem earlier:
It looks very simple, but the effect of this wrapper type is incredible; most things in functional
programming are very basic but with tremendous impact and reach. I’ll refactor safeDivide earlier
to return a SafeNumber:
Higher-order PHP 25
One thing I like about this function is how honest it is about its return type. It’s essentially notifying
the caller that something might go wrong, and that it’s safe to protect the result. Also, it removes
the burden of having to NAN-check any functions that are invoked with this value. I’ll show the
cases of calling safeDivide with a valid as well as an invalid denominator:
SafeNumber abstracts out the details of dealing with an invalid number, so that we’re left alone to
worry about bigger, more important problems.
In chapter 1, I briefly mentioned that behind the scenes, all functions are instances of the Closure
class. This is what enables me to map them to containers. This is important to understand, so let’s
take another look at this class.
Closures
After PHP 5.4+, all functions in PHP are objects created from the Closure class. But why do we call
it this way and not the more intuitive Function type (like JavaScript)? The goal behind this class
is to represent anonymous functions⁶ where a closure is formed around the function as it’s being
inlined into, say, a callable argument. For instance, I could use an anonymous function to perform
the safe divide (I would recommend you do this only when the function is unique to the problem
you’re solving and you don’t anticipate reusing it somewhere else):
⁶http://php.net/manual/en/functions.anonymous.php
Higher-order PHP 26
1 apply2(
2 function (float $a, float $b): SafeNumber {
3 return SafeNumber::of(empty($b) ? NAN : $a / $b);
4 })
5 (7, 2); //-> Container [3.5]
They are also used extensively in modern MVC frameworks, like Laravel:
But this doesn’t apply exclusively to the anonymous case, all functions create a closure. Unfor-
tunately, at this point PHP doesn’t have support for “lambda expressions,” syntactically simpler
anonymous functions, but there’s currently an open proposal that I hope will be included soon.
Check out this RFC here⁷ for more information.
With lambda expressions and omitting type declarations, the code above would look pretty slick:
Similarly, lambda functions would also be implemented to form a closure around it. Let’s understand
what this means. A closure is defined as the lexical scope created around a function declaration,
anonymous or otherwise. This gives function knowledge of the state of the variables lexically
declared around it. The term lexical refers to the actual placement of the variable in the code. Here’s
a diagram that explains what a function inherits:
⁷https://wiki.php.net/rfc/arrow_functions
Higher-order PHP 27
The data structure used to encapsulate the state that makes up a function’s closure is the [Closure
class](http://php.net/manual/en/class.closure.php) class, hence the name. Here’s the definition for
it:
1 class Closure {
2 private __construct ( void )
3 public static Closure bind ( Closure $closure , object $newthis [, mixed $new\
4 scope = "static" ] )
5 public Closure bindTo ( object $newthis [, mixed $newscope = "static" ] )
6 public mixed call ( object $newthis [, mixed $... ] )
7 }
Recall the function concatWith used earlier, and look closely at the inner function:
PHP’s closure mechanism has an advantage over that of JavaScript’s in that, instead of simply
capturing all of the state around an anonymous function declaration, you can explicitly declare
which variables the it’s permitted to access via the use keyword.
This is incredibly powerful and allows you to have more control over side effects. Under the hood,
the variables passed into use are used to instantiate its closure.
Here are some examples that reveal PHP’s internal closure object. The add function can be invoked
as globally using Closure::call⁸:
The use of PHP 7’s anonymous class here is to set the owning class of this function (in case $this is
used) to something concrete. Since I don’t use $this, I can provide a meaningless object to receive
$this.
You can also dynamically bind functions to object scopes using Closure::bindTo⁹. This allows you
to easily mixin additional behavior of an existing object. As example, let’s create a function that
⁸http://php.net/manual/en/closure.call.php
⁹http://php.net/manual/en/closure.bindto.php
Higher-order PHP 28
allows us to validate the contents inside a container before mapping an operation to it. In functional
programming, conditional validation is applied using an operator called filter, just like array_-
filter¹⁰ is used to remove unnecessary elements. But instead of adding filter to all containers, I
can mixin a properly scoped closure (in some ways this is similar to using Traits¹¹):
1 function addTo($a) {
2 return function ($b) use ($a) {
3 return $a + $b;
4 };
5 }
6
7 $filter = function (callable $f): Container {
8 return Container::of(call_user_func($f, $this->_value) ? $this->_value : 0);
9 };
10
11 $wrappedInput = Container::of(2);
12
13 $validatableContainer = $filter->bindTo($wrappedInput, Container);
14
15 $validatableContainer('is_numeric')->map(addTo(40)); //-> 42
Now consider what happens when the input is invalid according to our filter predicate:
1 $wrappedInput = Container::of('abc);
2 $validatableContainer('is_numeric')->map(addTo(40)); //-> 40
Now that you’ve learned about higher-order functions (and then some more), we’re ready to begin
creating functional programs. In chapter 3 we’ll learn about function composition and point-free
programs, as well as how to break problems apart into manageable, testable units.
Lastly, if you have an OOP background, here’s a nice table to keep handy that compares both
paradigms which will make the rest of the material easier to digest.
¹⁰http://php.net/manual/en/function.array-filter.php
¹¹http://php.net/manual/en/language.oop5.traits.php
Higher-order PHP 29