michielovertoom.com

Functional PHP • 6 Jun 2011

Many years ago I made static websites, not only for myself, but also for companies, as a freelancer. Some of these companies asked me if I could make their site more dynamic, so that they could maintain their content with some CRUD forms instead of editing static HTML. I knew that many providers were offering price-competetive dynamic hosting for that, using MySQL and PHP, mostly running on Linux servers. The writing on the wall was clear: I had to bite the bullet and learn how to make dynamic web applications.

To learn this new PHP language I scoured the web for examples and tutorials. I think it must have been around 1995 and 1996 or so. Looking at the examples, I was suprised how tangled and confused they looked: I saw HTML markup interspersed with snippets of PHP code and static content, magic markers everywhere, and even big hulking SQL queries in the middle of webpages.

A better place

"When I'm going to redo my websites in PHP", I thought, "I'm not going to write that makeshift crap." So I set out to separate content from program code by using a template processor. This got rid of the horrible intermingling of static HTML with PHP code. Later on I also managed to separate content from style by using CSS.

I was left with reasonably clean PHP code, a set of templates, a few database tables and a CSS style file. While honing my PHP skills I recognized that I was converging towards a certain pattern for my webapps:

// index.php include("somefile.php"); include("someotherfile.php"); // Do some global stuff like setting error_reporting, connecting to the database, etc... // Here be functions. // Dispatcher. if ($action == "") echo homepage(); else if ($action == "products") echo productspage(); else if ($action == "productdetail") echo productdetailpage($productid); else echo pagenotfound();

What I was doing was basically making a dispatcher which looked at the query string and call different functions for each type of page; some pages were parametrized. Each page function would produce the HTML necessary to render the page.

Years later I also began experimenting with 'route dispatchers', which would look at the path part of the URI instead of the query string to determine which function to call. Many people will recognize them as so-called 'search engine friendly' URL's, for example "http://example.org/chemicals/household/detergent/236". Nowadays we have all kinds of nice frameworks (like CodeIgniter) for that, but back then these didn't exist yet, so we had to write our own dispatchers.

Functional approach

I preferred to write functions that had no side effects (i.e., did not change variables outside the function), and that always returned the same result for the same input parameters. When I had to do some transformation on a collection, for example: selecting all articles in stock from a large array of all articles, I did this by creating a new array and copying the items I was interested in into it, and returned this new array, so that the existing arrays were never mutated:

function filteredarticles($articles, $criterium) { $result = array(); foreach ($articles as $key=>$value) if (satisfies($value->something, $criterium)) $result[] = $value; return $result; }

It's funny, but back then I hadn't heard of functional languages, yet I was practicing some principles of it. As a sidenote, the same thing happened with OOP-style programming using C. In self-written libraries, I used to name related function frob_init(), frob_start(), frob_end(), frob_finalize() etc.., every call passing an opaque struct around which held state for that particular instance on which the functions would work.

Embedding

Another pattern began to emerge. Every page on a website had the same 'encompassing decoration', call it ornamentation if you like -- header with logo, navigation menu, and footer. The only thing that set apart one page from another was the central content area. So I always seemed to come up with the following function, for every website:

function embed($centralcontent, $logoclickable, ...) { $t = new Template("site.tpl") $t->set("content", $centralcontent); ... return $t->render(); }

The template 'site.tpl' would contain all the page chrome and site stylings, from the DOCTYPE and head to the body, navigation and footer. The $centralcontent would be fed from other template expansions, which lacked these encompassing features, but were designed to work within the page in which they were to be embedded. I call them 'subtemplates' now. A page is often constructed from a diversity of subtemplate expansions, which eventually combine to the final resulting page.

A few contemporary templating engines nowadays implement this through 'template inheritance'.

Caching

Caching is broadly recognized as the #1 optimisation step you can take to make your website more performant and therefore more pleasant for your visitors.

Luckily one of the big advantages you can reap when programming in a functional style is that you can cache liberally (the other advantage is lazy evaluation, which PHP regrettably doesn't). In functional programming, it's a given that a function will always return the same result for the same input parameter. So if you cache the result of a function you can always return this cached value every time the same input comes in. At first I used the file system as a cache, but when memcached became available and I could exercise more control over the servers where my webapps were running, I switched to memcached. I hid the caching mechanism behind some wrapper functions, anyway:

function heavypage($somearg) { $cachekey = combine("heavypage", $somearg); if (incache($cachekey)) return getcache($cachekey); ... // compute heavy page here, in $content ... put($cachekey, $content); return $content; }

This pattern fits in nicely with the page-producing paradigm I was already using. I use this caching also for parts of pages, and even for results of database queries, if the chance that they'll occur multiple times is present. In Python you can even make a nice decorator which will provide this caching for any arbitrary function (as long as its a true function, of course!).

Stampede protection

Caches need to be invalidated from time to time, otherwise the information will cease to be up-to-date. Suppose you have a blog on which people can comment on each article. Getting the comments (and threading them) for a specific article might be a expensive operation, so that is a candidate for caching. However, you want a new comment to show up when somebody writes a new comment. That means you have to rebuild the page. That can be done of course by removing the corresponding cache entry so the page will be newly built the next time someone accesses it. But what if the site is a busy one, and 100 people at the same time try to access it? You'll have 100 simultaneous threads, processes or frontend requests (depending on your webserver setup) assembling this page, all at once. What a waste of resources! This is called the stampede problem.

One way to overcome the stampede is to leave the existing cache entry active until you've built a replacement. After a user add a comment, you call the page-producing function with an additional parameter which signals it to ignore the cache, yet update it with a more recent version of the page:

function heavypage($somearg, $ignorecache=false) { $cachekey = combine("heavypage", $somearg); if (!$ignorecache && incache($cachekey)) return getcache($cachekey); ... // compute heavy page here, in $content ... put($cachekey, $content); return $content; } ... // When a user add a comment for $articlenr, also execute: heavypage($articlenr, true); ...

Yet again this is an advantage of using a functional programming style. Would the function heavepage() have side-effects, this would not have been possible.

Conclusion

I hope you liked this humble exposé about functional programming style, as applied to PHP. It's nothing new: thousands of programmers were doing it for decades, and many more are doing this every day. But if you've never realised yourself that you were doing it, it can be a revelation.

This is the first draft of the article I write on this subject, and I have still the feeling it's a bit shallow. Maybe I'll extend it later on.

Greetings,
Michiel Overtoom

Comments

jcubic • 13 Feb 2012

What about closures and higher order functions? Puting your code into functions is not functional programming it's more likly structured programming.

Tobias Sjösten • 16 Feb

I recently found a project with functional primitives for PHP which helps in applying a functional programming style. It exists both as a userland library and a C extension. Check it out if you're longing for a more consistent interface for FP goodness! http://vvv.tobiassjosten.net/php/functional-primitives-for-php/

Leave a comment

name (required)



content last edited on June 6, 2011, 20:56 - rendered in 11.46 msec