Functional style programming with Underscore.php


Underscore.php is a PHP port of the popular Underscore.js library. Underscore.php provides a utility library for PHP that provides a lot of the functional programming support that a programmer would expect in Ruby, but without adding much overhead during execution. The only caveat is that underscore.php requires PHP 5.3 or greater. Although you could accomplish some of the things using PHP’s built in functions, the functional style approach looks intuitive and easy to work with. Note that this not a purely functional programming like Haskell. It would be nice to integrate the library in your CakePHP framework, which will help bring some functional flavor to the framework.

Take a quick example of the ‘pluck’ method.

include_once('underscore.php');
 
$members= array(
  array('name'=>'bill', 'age'=>40, 'gender' => 'm'),
  array('name'=>'john', 'age'=>50, 'gender' => 'm'),
  array('name'=>'sarah','age'=>60, 'gender' => 'f')
);
 
$ret = __::pluck($members, 'name');
print_r($ret);


returns…

Array
(
    [0] => bill
    [1] => john
    [2] => sarah
)

Here is another using the ‘map’ method.

$ret = __::map(array(1, 2, 3), function($num) { return $num * 3; });
print_r($ret);

returns…

Array
(
    [0] => 3
    [1] => 6
    [2] => 9
)

Underscore.php works in both object-oriented and static styles. The following lines give the examples of both.

$members= array(
  array('name'=>'bill', 'age'=>40, 'gender' => 'm'),
  array('name'=>'john', 'age'=>50, 'gender' => 'm'),
  array('name'=>'sarah','age'=>60, 'gender' => 'f')
);
 
/* Static style */
$ret = __::max($members, function($member) { return $member['age']; });
 
/* Object Oriented style */
$ret = __($members)->max(function($member) { return $member['age']; });
 
print_r($ret);

returns…

Array
(
    [name] => sarah
    [age] => 60
    [gender] => f
)

Another example using the ‘template’ method.

$members = array(
  array('name'=>'bill', 'age'=>40, 'gender' => 'm'),
  array('name'=>'john', 'age'=>50, 'gender' => 'm'),
  array('name'=>'sarah','age'=>60, 'gender' => 'f')
);
 
$template = '<% __::each($members, function($member) { 
             %> <li><%= $member["name"] %></li> <% }); %>';
 
$ret = __::template($template, array('members'=>$members));
 
print_r($ret);

returns…

<li>bill</li>  
<li>john</li>  
<li>sarah</li>

How does it work

The underscore.php files defines a ‘__’ class which encapsulates all the functional methods and uses the functional programming ideas introduced in PHP 5.3.

// Underscore.php
 
class __ {
  // Return an array of values by mapping each item through the iterator
  public function map($collection=null, $iterator=null) {
     ...
  }
  .
  .
  /* other methods */
}

Presently the library supports the following methods.

Collections
each, map, reduce, reduceRight, detect, select, reject, all, any, includ, invoke, pluck, max, min, groupBy, sortBy, sortedIndex, toArray, size

Arrays
first, rest, last, compact, flatten, without, uniq, union, intersection, difference, zip, indexOf, lastIndexOf, range

Functions
memoize, throttle, once, after, wrap, compose

Objects
keys, values, functions, extend, defaults, clon, tap, isEqual, isEmpty, isObject, isArray, isFunction, isString, isNumber, isBoolean, isDate, isNaN, isNull

Utility
identity, times, mixin, uniqueId, template

Chaining
chain, value

This site is a digital habitat of Sameer Borate, a freelance web developer working in PHP, MySQL and WordPress. I also provide web scraping services, website design and development and integration of various Open Source API's. Contact me at metapix[at]gmail.com for any new project requirements and price quotes.

1 Response

1

Tobias Sjösten

February 16th, 2013 at 2:43 am

Another attempt at this is the “Functional primitives for PHP”; which I believe does a better job at porting the Underscore.js functionality to proper PHP idioms. Check it out if you’re interested!

http://vvv.tobiassjosten.net/php/functional-primitives-for-php/

Your thoughts