Home Development of Websites Functional Programming in PHP

Functional Programming in PHP

by admin

PHP has always been a simple, procedural programming language that took its inspiration from C and Perl.PHP 5 introduced a proper object model, but you already know all about it.In PHP 5.3, on the other hand, closure was introduced and was vastly improved upon in 5.4 (hint : $this is now available by default).

What is functional programming after all?

It’s been a few years since I started using functional elements in my source code, but I’m still not ready to give a direct and precise answer to this question. And yet, despite the fact that I don’t have a clear definition yet – I can confidently say when I have an example of functional programming in front of me and when I don’t. So I’ll try to come at it from a slightly different angle: functional programs usually don’t resort to changing states, but use pure functions. These pure functions take a value and returna value without changing their input argument. The opposite example is a typical setter in an object-oriented context.
A typical functional programming language also supports high-order functions, which are functions that take as arguments or return other functions. Most of them support such things as carring ( currying ) and partial functionapplication( partial function application ). Also, in functional programming languages you can find an elaborate type system that uses option type to prevent null pointers, which have become commonplace in imperative or object-oriented programming languages.
Functional programming has several seductive properties: the lack of fiddling with states makes parallelism easier (but not easy – parallelism is never easy), focusing on a function – a minimal unit of code which can be used again – can lead to interesting things related to its reuse; requiring functions to be defined is a great idea for creating stable programs.

What does PHP have to offer?

PHP is not a "real" or "pure" functional language. It is far from that. There is no proper type system, " tough guys. " are rolling with laughter at our exotic syntax for closures, and there’s also a function array_walk() which looks functional at first glance, but allows to change states.
Nevertheless, here are some interesting "building blocks" for functional programming purposes. For starters, let’s take call_user_func , call_user_func_array and $callable()call_user_func Takes a callback function and a list of arguments, then calls that callback with the passed arguments. call_user_func_array does the same thing, except it takes an array of arguments. This is very similar to fn.call() and fn.apply() in JavaScript (without passing the scope). A much lesser known but great feature in PHP 5.4 is the ability to call functions. callable is a meta-type in PHP (i.e. consisting of several nested types): callable can be a string to call simple functions, an array of <string, string> for calling static methods, and by an array of <object, string> for calling methods of an object, an instance of Closure or anything that implements the magic method __invoke() also known as the Functioner. It looks something like this :

$print = 'printf';$print("Hello %sn", 'World');

PHP 5.4 introduces a new "callable" type, which allows easy access to the callable meta-type.
PHP also supports anonymous functions. As mentioned earlier, the Haskell community is laughing heartily at this fact, but the main thing is that we finally got them. And the jokes were quite expected, because the syntax of the expressions has become very heavy. Let’s take a simple example in Python.

map(lambda v: v * 2, [1, 2, 3])

Nice, now let’s look at the same code for Ruby:

[1, 2, 3].map{|x| x * 2}

Also not bad, although we had to use a block and a non-strict lambda expression. Ruby also has lambda expressions, but List.maphappens takes a block, not a function. Let’s move on to Scala:

List(1, 2, 3).map((x: Int) => x * 2)

As you can see from the examples, for a strictly typed programming language, the syntax is always quite compact. Let’s rewrite our example in PHP:

array_map(function ($x) {return $x * 2;}, [1, 2, 3]);

Keyword function and no implicit return makes the code look a bit cumbersome. But it works nonetheless. Another "building block" to the piggy bank for functional programming.
By the way, array_map is a good starting point, but it’s worth considering that there are also array_reduce ; here are two more important functions.

Functional example from the real world

Let’s write a simple program that calculates the total price of a shopping cart :

$cart = [['name' => 'Item 1', 'quantity' => 10, 'price' => 9.99, ], ['name' => 'Item 2', 'quantity' => 3, 'price' => 5.99, ]];function calculate_totals(array $cart, $vatPercentage){$totals = ['gross' => 0, 'tax' => 0, 'net' => 0, ];foreach($cart as $position) {$sum = $position['price'] * $position['quantity'];$tax = $sum / (100 + $vatPercentage) * $vatPercentage;$totals['gross'] += $sum$totals['tax'] += $tax$totals['net'] += $sum - $tax;}return $totals;}calculate_totals($cart, 19);

Yes, this is a very simple example which will only work for one store. But it doesn’t use too complex calculations and because of that we can easily redesign it to a more functional style.
Let’s start by using higher order functions :

$cart = [['name' => 'Item 1', 'quantity' => 10, 'price' => 9.99, ], ['name' => 'Item 2', 'quantity' => 3, 'price' => 5.99, ]];function calculate_totals(array $cart, $vatPercentage){$cartWithAmounts = array_map(function (array $position) use ($vatPercentage) {$sum = $position['price'] * $position['quantity'];$position['gross'] = $sum;$position['tax'] = $sum / (100 + $vatPercentage) * $vatPercentage;$position['net'] = $sum - $position['tax'];return $position;}, $cart);return array_reduce($cartWithAmounts, function ($totals, $position) {$totals['gross'] += $position['gross'];$totals['net'] += $position['net'];$totals['tax'] += $position['tax'];return $totals;}, ['gross' => 0, 'tax' => 0, 'net' => 0, ]);}calculate_totals($cart, 19);

Now there is no change of states, even within the function itself. array_map() returns a new array from the list of items in the shopping cart with weight, tax, and cost, and the function array_reduce puts together an array of totals. Can we go further? Can we make the program even simpler?
What if we break the program down even smaller and see what it actually does :

  • Sums up the array element multiplied by another element
  • Takes a fraction of the percentage of this sum
  • Counts the difference between the interest and the amount

Now we will need a little helper. That little helper will be functional-php , a little library of functional primitives that I’ve been developing for a few years now. For starters, there are Functionalpluck() which does the same thing as _.pluck() from underscore.js Another useful function from there is Functionalzip() It "compresses" two lists together, optionally using a callback function. Functionalsum() Sums the elements in the list.

use Functional as F;$cart = [['name' => 'Item 1', 'quantity' => 10, 'price' => 9.99, ], ['name' => 'Item 2', 'quantity' => 3, 'price' => 5.99, ]];function calculate_totals(array $cart, $vatPercentage){$gross = Fsum(Fzip(Fpluck($cart, 'price'), Fpluck($cart, 'quantity'), function($price, $quantity) {return $price * $quantity;}));$tax = $gross / (100 + $vatPercentage) * $vatPercentage;return ['gross' => $gross, 'tax' => $tax, 'net' => $gross - $tax, ];}calculate_totals($cart, 19);

An excellent counterargument immediately arises: is it true that the example has become easier to read? At first glance, definitely not, but from the second and beyond, you get used to it. Personally, it took me some time to get used to Scala syntax; it took me some time to learn OOP, and it took me quite a while to understand functional programming. Is this the most perfect form you can turn a source example into? No. But with this code you saw how much your approach to it changes when you think in terms of applying functions to data structures, rather than using expressions like foreach to handle the data structures.

What else can be done?

Have you ever encountered null pointer exceptions( null pointer exceptions )? There is such a thing as php-option which gives us an implementation of the polymorphic type "maybe" with a PHP object.
This has a partial use : it turns a function that takes n parameters into a function that takes <n parameters. How can this be useful? Take the extraction of the first character from a list of strings.
Boring path :

$list = ['foo', 'bar', 'baz'];$firstChars = [];foreach ($list as $str) {$firstChars[] = substr($str, 0, 1);}

Functional path without PFA (partial application of functions):

array_map(function ($str) {return substr($str, 0, 1);}, ['foo', 'bar', 'baz']);

Path with PFA and using reactphp/curry (my favorite implementation of curry for PHP):

use ReactCurry;array_map(Currybind('substr', Curry…(), 0, 1), ['foo', 'bar', 'baz']);

Yes. … (HORIZONTAL ELLIPSIS, U+2026) is the correct PHP function name. But if for some reason you don’t like it that much, you can use useCurryplaceholder()

That’s all

Functional programming is a very fascinating subject; if I were asked what has been the most important thing I’ve learned in recent years, I’d immediately say familiarity with functional paradigms. It’s so unlike anything you’ve tried before that your brain will hurt. Well, in a good way.
And lastly : read " Functional programming in the real world " ( Real World Functional Programming. ). It’s full of good advice and examples of practical use.
I look forward to your comments and corrections to the article in private messages.

You may also like