Leveraging PHP 5.3's lambdas and closures

Becoming a better developer with lambdas and closures

Find out how to use PHP 5.3's lambdas and closures. Discover why you should consider using them and how doing so can reduce the complexity of your code. Finally, learn the behaviors of closure's lexically scoped variables.

Don Denoncourt (dondenoncourt@gmail.com), Author, Consultant

Don Denoncourt is a free-lance consultant, trainer, mentor, and author specializing in Java technology, Groovy, Grails, and PHP. You can reach him at dondenoncourt@gmail.com.



07 December 2010

Also available in Japanese

In the past few years, there has been a lot of activity around programming languages. Developers have been studying languages like Ruby, Groovy, and Clojure — not just to broaden their marketability but also to expand their thinking. Two of the more exciting features of these languages are now available with PHP 5.3: lambdas and closures. And there's another language that most PHP developers already use that has an excellent implementation of lambdas and closures: JavaScript.

With the addition of lambdas and closures, PHP complies with the requirements of a functional programming language. Specifically, functional programming languages must provide high-order and first-class functions, which this article defines. In the past couple of years, interest in functional programming has skyrocketed. Why? Simple: Moore's law, which states that computing power will double every two years, is really no longer true. It is only somewhat not true because whereas computing power had been increased on a single-core processor, computer manufacturers can now only increase capacity by creating multi-core processors. That's why we've been seeing dual-, quad-, and hexa-core processors. Making multi-core processors is relatively easy for computer manufactures, but stateful, stacked-based languages don't necessarily benefit from additional processors. Functional programming languages can.

Just what are lambdas and closures and why should a PHP developer get excited about their availability? This article describes how and where to use lambdas and closures, exposes you to some of the behavioral peculiarities of closures, and introduces you to a few code idioms you can use to take advantage of lambdas and closures.

Lambdas: quick and simple

The term lambda is from Lambda calculus, a formal system for function definition, application, and recursion introduced by Alonzo Church in the 1930s. One interesting thing about Mr. Church is that his co-workers at Stanford University included Alan Turing of the famous Turing machine. The ideas that these two men formulated became the basis for modern programming languages.

But don't let the complexity of calculus dissuade you from using lambdas: They are really nothing more than anonymous functions. The following function definition, for example, is a lambda:

$horse = function() {return "with no name";};
print $horse();

Note that the semicolon (;) terminator is required, as the function is being assigned to a variable. Prior to PHP 5.3, you would have created a standard function:

function horse() {return "Secretariat";}
print horse();

"Big deal!" you say. "Both examples have the same number of lines, and besides — the nameless function basically did have a name in the $horse variable." Actually, $horse is a reference to a function, not the name of the function. But the real advantage to lambdas is when you create functions on the fly and no variable reference is required. For example:

$a=array('PA'=>"Pennsylvania",'VA'=>"Virginia",'TX'=>"Texas");
print_r(array_filter($a,
                     function($v){return $v==="Virginia";}
                    )
);

In this case, the lambda function remains nameless: It is created inline as a parameter to the array_filter function. Creating lambdas on the fly as parameters to functions and methods is lambda's primary use case. Note that the term callback is typically used to describe functions that are passed as parameters to other functions. Callbacks are frequently used in event handling architectures, where you designate code to be invoked at a later time.

In functional programming, lambdas are referred to as first-class functions because they can be:

  • Passed as a parameters.
  • Created and used at run time.
  • Returned from a function.
  • Assigned to variables.

In truth, lambdas have been available to PHP developers since V4.0 with the use of create_function:

$horse = create_function('', 'return "with no name";');
print $horse();

But the syntax for create_function is clunky. For one thing, the code is in one big quoted string. So don't expect any assistance from your PHP editor, and don't forget to escape that code string. Furthermore, the code for create_function is compiled at execution time, and the resulting function cannot be cached.


Asserting lambdas

Here's a simple example that uses a lambda — one that I will use throughout the rest of this article. Here's the application requirement: When I read PHP articles that contain code snippets, they typically show results with an echo or print followed by a comment that describes the expected output. Consider, for example, the following code:

function horse() {return "Secretariat";}
print horse(); // should list: Secretariat

The reader needs to run the code and visually verify the implied assumption. When I read:

print horse(); // should list: Secretariat

I feel like I'm going cross-eyed as I oscillate between the code and the comment. To make this article's code snippets more readable, I use PHP asserts. For example:

assert(horse() == "Secretariat");

The configuration of PHP assertions allows you to specify a function to be called whenever assert is invoked. Of course, I used a lambda:

assert_options(ASSERT_CALLBACK, 
	function ($script, $line) {
		echo "assert failed file:$script line:$line ";
        }
);

When an assertion fails, the script name and line number will be output:

assert failed file:/var/www/closure_behavior.php line:13 PHP Warning: 
assert(): Assertion failed in /var/www/closure_behavior.php on line 13

An alternative to the use of a lambda in the assertion would have been:

function assertCallback($script, $line) {
	echo "assert failed file:$script line:$line ";}
);
assert_options(ASSERT_CALLBACK, assertCallback);

"And why is the lambda version better?" you might ask? Let me explain. Keep in mind that the non-lambda version defines a function that is only used in one place. Understand that code is read far more than it is written, so simplifying code is important. Whenever you define a named function, your reader attempts to put that function name in his or her brain cache, which needlessly complicates the reader's understanding of the program. If a function is to be a once-and-done operation, use a lambda and simply your code.

Throughout the rest of this article, whenever you see an assert, you can be sure that the assertion is true.


Beginning with closures

If lambdas are nothing more than nameless functions, then closures are little more than lambdas with a context. That is, a closure is an anonymous function that, when created, attaches to itself the value of variables from the scope of the code that created the function. Variables are bound to a closure with the use keyword. For example, if you have the following variables:

$states=array('PA'=>"Pennsylvania",'VA'=>"Virginia",'TX'=>"Texas");
$st = 'Texas';

You can bind the $st variable to the closure with the use keyword in the following example:

$tx = array_filter($states, function($v) use($st) {return $v==$st;});

Then assert success:

assert(array_keys($tx) == array('TX'));

As the above example illustrates, a closure is a function that is "closed over" specified variables. The above example is a good use case for closures: It uses one of the 18 standard PHP array functions that take a function as a parameter (such as array_walk, usort, and array_app). Closures allow you to expand the use of those utility functions. Before closures, implementation of the passed function was limited to the context of its function arguments. (Actually, that is not completely true, as you could have used globals. But it is conventional wisdom that the use of globals is a bad programming practice.)

PHP's array_filter is an example of what is know in functional programming as a higher-order function. A higher-order function (in both mathematics and computer science) is one that takes a function as input or outputs a function. After becoming comfortable with lambdas and closures, you may find yourself reducing code and creating more readable and reusable code by writing your own higher-order functions.

A closure is actually a new data type implemented internally with the new Closure class. Here's another way to look at it: If an object is data with methods that operate on that data, then a closure is a function with data bound to that function.


Closure behavior

It is easy to understand the syntax of a closure's use keyword. But it takes a bit of playing around with closures before you begin to understand the behavior of variables passed to closures via the use keyword. I'm sure you have a solid understanding of variable scope: Well-written code defines variables only in the scope for which it is required. With that in mind, you would expect the assertion at the end of the following code to fail:

function getNameFunc() {
     $string = 'Denoncourt';
     return function() use ($string) { return $string; };
}
$name = getNameFunc();
$name();
assert ($name() == 'Denoncourt');

But the assertion is successful — even though $string went out of scope. That's because variables specified in a closure's use keyword are lexically scoped. Let me explain: PHP variables are typically dynamically scoped, which means the variables are placed on a stack. Those variables pop off the stack when their containing function is complete. Lexically scoped variables refer to the local environment in which they were defined. Instead of being placed on a stack, the variables specified with the use keyword are stored in static storage.

It is a powerful feature of closures that — regardless of where they are defined—they can be called later, from anywhere, and executed with their use-specified variables still in a valid scope. Be aware, however, that PHP's implementation of lexical scope copies variables specified in the use keyword into the static storage area. When using large objects, you can reduce storage by passing a reference to the variable, like so:

$string = 'Denoncourt';
$changeName = function() use(&$string) {$string = 'Smith';};
$changeName();
assert ($string == 'Smith');

As the above example also shows, passing use variables by reference is one way you can allow the closure to modify values.

"Wait a minute," you say. "Why not just pass the variable that you passed in the closure's use option as a function argument?" That's where the power of lexically scoped variables comes into play. With function arguments, the parameters passed must be in stack scope. But, with use variables, the closure essentially remembers the context of the variable. Consider the example in Listing 1, where a closure is defined in a class, and then invoked after the object variable goes out of scope.

Listing 1. Invoking a closure after the variable goes out of scope
class Person {
	var $first;
	var $last;
	public function sayHello() {
		$that = $this;
		return function() use ($that) { 
			return $that->first.' '.$that->last; 
        	};
	}
}
function stackFunc1() {
	$me = new Person();
	$me->first = 'Don';
	$me->last = 'Denoncourt';
	return $me->sayHello();
}
$sayHi1 = stackFunc1(); 
function stackFunc2() {
	$me = new Person();
	$me->first = 'Sue';
	$me->last = 'Swartzbaugh';
	return $me->sayHello();
}
$sayHi2 = stackFunc2(); 
assert($sayHi1() == 'Don Denoncourt');
assert($sayHi2() == 'Sue Swartzbaugh');

Note that the Person::sayHello method implementation creates an alias for the $this special variable and passes that to the closure definition. That is because a closure is internally implemented with the Closure class, and that class has its own $this context. In fact, if you pass $this in the use keyword, you will get an error similar to this:

PHP Fatal error:  Cannot use $this as lexical variable

The use cases for class methods that return functions is limited only by your creativity. For an example of the creative use of closures, check out Pawel Turlejski's utility class, which provides Groovy-like array methods (see Resources).

With the use of closures, you can even code your classes to allow the dynamic creation of methods. Listing 2 provides an example.

Listing 2. Coding with dynamic method creation
class Person {
    var $first;
    public function __call($method, $args) {
        return call_user_func_array( $this->$method, $args);
    }
}
$me = new Person();
$me->first = 'Don';
$me->sayGoodbye = function() use ($me) {
    return 'Bye '.$me->first;
};
assert($me->sayGoodbye() == 'Bye Don');

Again, even if the object goes out of scope, the closure can be successfully invoked. For example, the above closure execution works even if you removed the $me object reference with PHP's unset method:

$bye = $me->sayGoodbye;
unset($me);
assert($bye() == 'Bye Don');

Arguments passed to higher-order functions, and then passed on as arguments to a closure's use keyword also retain their values:

$greeting = function($greet) {
	return function($name) use($greet) {
		return $greet.' '.$name;
	};
};
$hi=$greeting('Yoh');
assert($hi('Don') == "Yoh Don");
assert($hi('Sue') == "Yoh Sue");

Invoking classes

Earlier, I mentioned that closures were implemented internally with a class called Closure. (That class, by the way, may change in subsequent versions of PHP, so don't use it directly in development.) But there is one feature of the implementation internals of the Closure class that you can exploit: its use of the new __invoke method. The __invoke magic method makes a class callable:

class Invoker {
	public function __invoke() {return __METHOD__;}
}
$obj = new Invoker;
assert ($obj() == 'Invoker::__invoke');

When a class that contains an implementation of __invoke is instantiated, you can call the class by specifying parentheses (()) following an object name. This type of object is known as a functor or function object.


Close for sure

Your applications can benefit from the use of lambdas and closures. By replacing formal function definitions with anonymous functions, you simplify code. By developing utility functions and methods as higher-order functions, you make your applications more robust. By understanding closures and lexical scope, you begin to perceive opportunities for new development patterns and idioms. And by learning more about functional programming, you broaden yourself as a developer.

Should PHP be used as a functional programming language? In general, no: PHP evolved as a lean, simple language for the development of web applications. Developing PHP-based Web applications using purely functional semantics goes against the original intent of the language. In any case, PHP's syntax for lambdas and closures is somewhat inelegant (especially when compared with languages like Ruby, Groovy, and Clojure). But there are scenarios where the application of functional programming concepts can be applied to PHP applications, resulting in code that is simpler, more concise, and easier to understand.


Download

DescriptionNameSize
Sample PHP scripts for this articleos-php-lambda-Closure_example.zip4KB

Resources

Learn

Get products and technologies

Discuss

Comments

developerWorks: Sign in

Required fields are indicated with an asterisk (*).


Need an IBM ID?
Forgot your IBM ID?


Forgot your password?
Change your password

By clicking Submit, you agree to the developerWorks terms of use.

 


The first time you sign into developerWorks, a profile is created for you. Information in your profile (your name, country/region, and company name) is displayed to the public and will accompany any content you post, unless you opt to hide your company name. You may update your IBM account at any time.

All information submitted is secure.

Choose your display name



The first time you sign in to developerWorks, a profile is created for you, so you need to choose a display name. Your display name accompanies the content you post on developerWorks.

Please choose a display name between 3-31 characters. Your display name must be unique in the developerWorks community and should not be your email address for privacy reasons.

Required fields are indicated with an asterisk (*).

(Must be between 3 – 31 characters.)

By clicking Submit, you agree to the developerWorks terms of use.

 


All information submitted is secure.

Dig deeper into Open source on developerWorks


static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=1
Zone=Open source
ArticleID=594436
ArticleTitle=Leveraging PHP 5.3's lambdas and closures
publish-date=12072010