- jason@ratchet Desktop $ /usr/local/bin/php closure.php
- 0
- 1
- 2
- 3
Finding the arity of a closure in PHP 5.3
As part of the php-helpers project I’ve been working on a small library of functional programming primitives for PHP 5.3, including all the usual suspects like map(), every() and inject(). As we know, PHP arrays are really ordered maps, and when iterating with foreach we’re sometimes interested in both the key and value and other times it’s only the value we’re after. Preferably, code written in a functional style would be consistent with this pattern, each operation employing a single function capable of intelligently passing either $key, $value or `$value` based on what the user-specified lambda expected. So is this possible in PHP?
Arity to the rescue
From Wikipedia: “the arity of a function or operation is the number of arguments or operands that the function takes.”. Bingo. If we could somehow find the arity of a given closure, we could use this to decide whether to pass $key, $value or simply $value to our anonymous function. A language like Ruby makes finding a lambda’s arity as simple as foo.arity, but PHP isn’t quite so elegant, instead requiring us to whip out a bit of reflection:
- <?php
- $c0 = function() {};
- $c1 = function($a) {};
- $c2 = function($a, $b) {};
- $c3 = function($a, $b, $c) {};
- foreach (array($c0, $c1, $c2, $c3) as $c) {
- $r = new ReflectionObject($c);
- $m = $r->getMethod('__invoke');
- echo $m->getNumberOfParameters() . "\n";
- }
- ?>
I’ll refrain from any puns alluding to vulgarity. Anyway, this yields the desired result:
Here’s the arity() function, and the resulting implementation of every(), taken directly from functional.php:
- // returns the arity of the given closure
- function arity($lambda) {
- $r = new ReflectionObject($lambda);
- $m = $r->getMethod('__invoke');
- return $m->getNumberOfParameters();
- }
- function every($iterable, $lambda) {
- if (arity($lambda) < 2) {
- foreach ($iterable as $i) $lambda($i);
- } else {
- foreach ($iterable as $k => $v) $lambda($k, $v);
- }
- }
The lack of closures in PHP has long been one of the language’s most frustrating shortcomings when compared to its rivals, and their addition is – at least for me – the most exciting change in 5.3. While PHP will probably never be regarded as a “beautiful” language, closures allow us to write code which is both more flexible and concise by making it possible to define behaviour directly in the context it is being used, rather than having to implement it elsewhere in auxiliary classes or functions. Get on the bandwagon!

