September 26, 2008

Closures in PHP 5.3

If early releases are any indication, PHP is scheduled to receive some pretty significant updates in version 5.3. In addition to namespaces, I'm particularly interested in the addition of closures.

According to object-oriented programming expert Martin Fowler, closures are defined as a block of code that can be passed to a function. However, delegates (C#), anonymous classes (Java) and function pointers (C) don't quite qualify because the following also needs to be true:
  1. Closures need to be able to refer to variables already present in scope at the time they're defined.

  2. Closures shouldn't require complex syntax (I personally think this point is a tad subjective).
As you can imagine this capability might be helpful when writing a function that repeatedly executes a block of code specific to the function. It wouldn't make sense to refactor this block of code to the class level if it doesn't get used anywhere outside the function. With closures, the block of code distinct to the function may be defined and repeatedly called upon without having to bloat your classes.

PHP's upcoming syntax for closures is shaping up to be comparable to the C# 2.0 implementation. In the .NET world closures first arrived as anonymous methods in C# 2.0 (these were later simplified into lambda expressions in C# 3.0).

For comparison's sake C# anonymous methods look something like this:
/* Returns true if tOne and tTwo are  both evenly 
divisible by the denominator (denom) */
public bool EvenlyDivisible(int denom, int tOne, int tTwo)
{
//Define the closure
Predicate evenlyDivisible = delegate(int testNum)
{
//Note that denom is defined outside closure scope
if ((testNum % denom) == 0)
{
return true;
}
else
{
return false;
}
};

//Use the closure as necessary
if (evenlyDivisible(tOne) && (evenlyDivisible(tTwo)))
{
return true;
}
else
{
return false;
}
}
When released, a comparable implementation in PHP 5.3 will probably look something like the following:
/* Returns true if $tOne and $tTwo are  both evenly 
divisible by the denominator ($denom) */
function EvenlyDivisible($denom, $tOne, $tTwo)
{
$evenlyDivisible = function ($testNum) use ($denom) {
//Note that $denom is defined outside closure scope
if (($testNum % $denom) == 0)
{
return true;
}
else
{
return false;
}
};

//Use the closure as necessary
if ($evenlyDivisible($tOne) && ($evenlyDivisible($tTwo)))
{
return true;
}
else
{
return false;
}
}
For additional information please check out the closure proposal on php.net.