What's new in PHP V5.3, Part 2: Closures and lambda functions

Follow along in this "What's new in PHP V5.3" series of articles that covers the new and exciting features found in PHP V5.3, which is scheduled to release soon. Part 1 looks at the changes made to the object-oriented programming and object handling in PHP V5.3. Here in Part 2, we look at closures and lambda functions. They are designed to make programming much easier by allowing you to easily define throwaway functions that can be used in many contexts.

John Mertic, Software Engineer, SugarCRM

John Mertic graduated with a degree in computer science from Kent State University and is currently a software engineer at SugarCRM. He has contributed to many open source projects, most notably PHP projects; he is the creator and maintainer of the PHP Windows Installer.



09 December 2008

Also available in Russian Japanese Vietnamese

The concepts of closures and lambda functions are definitely not new ones; they both come from the functional programming world. Functional programming is a style of programming that moves the focus from executing commands to the evaluation of expressions. These expressions are formed using functions, which are combined to get the results we may be looking for. This style of programming was more often used in an academic setting, but it is also seen in the realms of artificial intelligence and mathematics, and can be found in commercial applications with languages like Erlang, Haskell, and Scheme.

Closures were originally developed in the 1960s as part of Scheme, one of the most well-known functional programming languages. Lambda functions and closures are often seen in languages that allow functions to be treated as first-class values, meaning that the functions can be created on the fly and passed as parameters to other languages.

Since that time, closures and lambda functions have found their way out of the functional programming world and into languages like JavaScript, Python, and Ruby. JavaScript is one of the most popular languages that supports closures and lambda functions. It actually uses them as a means to support object-oriented programming, where functions are nested inside other functions to act as private members. Listing 1 provides an example of how JavaScript uses closures.

Listing 1. A JavaScript object built using closures
var Example = function()
{ 
    this.public = function() 
    { 
        return "This is a public method"; 
    }; 

    var private = function() 
    { 
        return "This is a private method"; 
    };
};

Example.public()  // returns "This is a public method" 
Example.private() // error - doesn't work

As we see in Listing 1, the member functions of the Example object are defined as closures. Since the private method is scoped to a local variable (vs. the public method attached to the Example object using this keyword), it is not visible to the outside world.

Now that we've seen some historical perspective on where these concepts have come from, let's look at lambda functions in PHP. The concept of lambda functions is the basis for closures and provides a much-improved way to create functions on the fly vs. the create_function() function already in PHP.

Lambda functions

Lambda functions (or "anonymous functions," as they are often referred to) are simply throwaway functions that can be defined at any time and are typically bound to a variable. The functions themselves only exist in the scope of the variable of which they are defined, so when that variable goes out of scope, so does the function. The idea of lambda functions comes from mathematics work back in the 1930s. Known as lambda calculus, it was designed to investigate the function definition and application, as well as the concept of recursion. The work from lambda calculus was used to develop functional programming languages, such as Lisp and Scheme.

Lambda functions are handy for a number of instances, most notably for many PHP functions that accept a callback function. One such function is array_map(), which allows us to walk through an array and apply a callback function to each element of the array. In earlier versions of PHP, the biggest problem with these functions is that there wasn't a clean way to define the callback function; we were stuck taking one of three available approaches to the problem:

  1. We could define the callback function somewhere else in the code so we know it's available. This is somewhat ugly since it moves part of the implementation of the call elsewhere, which is rather inconvenient for readability and maintainability, especially if we aren't going to use this function elsewhere.
  2. We could define the callback function in the same code block, but with a name. While this does help keep things together, we need to add an if block around the definition to avoid namespace clashes. Listing 2 is an example of this approach.
    Listing 2. Defining a named callback in the same code block
    function quoteWords()
    {
         if (!function_exists ('quoteWordsHelper')) {
             function quoteWordsHelper($string) {
                 return preg_replace('/(\w)/','"$1"',$string);
             }
          }
          return array_map('quoteWordsHelper', $text);
    }
  3. We can use create_function(), which has been a part of PHP since V4, to create the function at runtime. While functionally, this does what we want, it has a few disadvantages. One major one is that it is compiled at runtime vs. compile time, which won't permit opcode caches to cache the function. It also is rather ugly syntax-wise, and the string highlighting present in most IDEs simply doesn't work.

Although the functions that accept callback functions are powerful, there isn't a good way to do a one-off callback function without some very inelegant work. With PHP V5.3, we can use lambda functions to redo the above example in a much cleaner way.

Listing 3. quoteWords() using a lambda function for the callback
function quoteWords()
{
     return array_map('quoteWordsHelper',
            function ($string) {
                return preg_replace('/(\w)/','"$1"',$string);
            });
}

We see a much cleaner syntax for defining these functions, which can be optimized for performance by opcode caches. We've also gained improved readability and compatibility with string highlighting. Let's build upon this to learn about using closures in PHP.


Closures

Lambda functions by themselves don't add much in terms of something we couldn't do before. As we saw, we could do all of this using create_function(), albeit with uglier syntax and less-than-ideal performance. But they are still throwaway functions and don't maintain any sort of state, which limit what we can do with them. This is where closures step in and take the lambda functions to the next level.

A closure is a function that is evaluated in its own environment, which has one or more bound variables that can be accessed when the function is called. They come from the functional programming world, where there are a number of concepts in play. Closures are like lambda functions, but smarter in the sense that they have the ability to interact with variables from the outside environment of where the closure is defined.

Let's take a look at how to define a closure in PHP. Listing 4 shows an example of a closure that will import a variable from the outside environment and simply print it out to the screen.

Listing 4. Simple closure example
$string = "Hello World!";
$closure = function() use ($string) { echo $string; };

$closure();

Output:
Hello World!

Variables to be imported from the outside environment are specified in the use clause of the closure function definition. By default, they are passed by value, meaning that if we would update the value passed within the closure function definition, it would not update the outside value. We can, however, do this by prefacing the variable with the & operator, which is used in function definitions to indicate passing by reference. Listing 5 shows an example of this.

Listing 5. Closure passing variables by reference
$x = 1
$closure = function() use (&$x) { ++$x; }

echo $x . "\n";
$closure();
echo $x . "\n";
$closure();
echo $x . "\n";

Output:
1
2
3

We see the closure using the outside variable $x and incrementing it each time the closure is called. We can mix variables passed by value and by reference easily within the use clause, and they will be handled without any problem. We can also have functions that directly return closures, as we see in Listing 6. In this case, the closure's lifetime will actually be longer than the method that has defined them.

Listing 6. Closure returned by a function
function getAppender($baseString)
{
      return function($appendString) use ($baseString) { return $baseString . 
$appendString; };
}

Closures and objects

Closures can be a useful tool not only for procedural programming but also for object-oriented programming. Using closures serves the same purpose in this situation as it would outside of a class: to contain a specific function to be bound within a small scope. They also are just as easy to use within our objects as they are outside an object.

When defined within an object, one handy thing is that the closure has full access to the object through the $this variable, without the need to import it explicitly. Listing 7 demonstrates this.

Listing 7. Closure inside an object
class Dog
{
    private $_name;
    protected $_color;

    public function __construct($name, $color)
    {
         $this->_name = $name;
         $this->_color = $color;
    }

    public function greet($greeting)
    {
         return function() use ($greeting) {
             echo "$greeting, I am a {$this->_color} dog named 
{$this->_name}.";
         };
    }
}

$dog = new Dog("Rover","red");
$dog->greet("Hello");

Output:
Hello, I am a red dog named Rover.

Here, we explicitly use the greeting given to the greet() method in the closure defined within it. We also grab the color and name of the dog, passed in the constructor and stored in the object, within the closure.

Closures defined within a class are fundamentally the same as those defined outside an object. The only difference is the automatic importing of the object through the $this variable. We can disable this behavior by defining the closure to be static.

Listing 8. Static closure
class House
{
     public function paint($color)
     {
         return static function() use ($color) { echo "Painting the 
house $color...."; };
     }
}

$house = new House();
$house->paint('red');

Output:
Painting the house red....

This example is similar to the Dog class defined in Listing 5. The big difference is that we don't use any properties of the object within the closure, since it is defined as static.

The big advantage of using a static closure vs. a nonstatic one inside an object is for the memory savings. By not having to import the object into the closure, we can save quite a bit of memory, especially if we have many closures that don't need this feature.

One more goody for objects is the addition of a magic method called __invoke(), which allows the object itself to be called as a closure. If this method is defined, it will be used when the object is called in that context. Listing 9 illustrates this.

Listing 9. Using the __invoke() method
class Dog
{
    public function __invoke()
    {
         echo "I am a dog!";
    }
}

$dog = new Dog();
$dog();

Calling the object reference shown in Listing 9 as a variable automatically calls the __invoke() magic method, making the class itself act as a closure.

Closures can integrate just as well with object-oriented code, as well as with procedural code. Let's see how closures interact with PHP's powerful Reflection API.


Closures and reflection

PHP has a useful reflection API, which allows us to reverse-engineer classes, interfaces, functions, and methods. By design, closures are anonymous functions, which means they do not appear in the reflection API.

However, a new getClosure() method has been added to the ReflectionMethod and ReflectionFunction classes in PHP for dynamically creating closure from the specified function or method. It acts like a macro in this context, where calling the method of function via the closure makes the function call in the context of where it's defined. Listing 10 shows how this works.

Listing 10. Using the getClosure() method
class Counter
{
      private $x;

      public function __construct()
      {
           $this->x = 0;
      }

      public function increment()
      {
           $this->x++;
      }

      public function currentValue()
      {
           echo $this->x . "\n";
      }
}
$class = new ReflectionClass('Counter');
$method = $class->getMethod('currentValue');
$closure = $method->getClosure()
$closure();
$class->increment();
$closure();
Output:
0
1

One interesting side effect of this approach is that it allows us to access private and protected members of a class via a closure, which can be handy for unit testing classes. Listing 11 is an example of accessing a private method in a class.

Listing 11. Accessing a private method in a class
class Example 
{ 
     ....
     private static function secret() 
     { 
          echo "I'm an method that's hiding!"; 
     } 
     ...
} 

$class = new ReflectionClass('Example');
$method = $class->getMethod('secret');
$closure = $method->getClosure()
$closure();
Output:
I'm an method that's hiding!

Also, we can use the reflection API to introspect a closure itself, as shown in Listing 12. We simply pass the variable reference to the closure into the constructor of the ReflectionMethod class.

Listing 12. Inspecting a closure using the reflection API
$closure = function ($x, $y = 1) {}; 
$m = new ReflectionMethod($closure); 
Reflection::export ($m);
Output:
Method [ <internal> public method __invoke ] {
  - Parameters [2] {
    Parameter #0 [ <required> $x ]
    Parameter #1 [ <optional> $y ]
  }
}

One thing to note in terms of backward-compatibility is that the class name Closure is now reserved by the PHP engine for storing closures, so any classes that use that name will need to be renamed.

The reflection API has great support for closures, as we've now seen, in the form of being able to create them from existing functions and methods dynamically. They can also introspect into a closure just like a normal function can.


Why closures?

As we saw in the examples for lambda functions, one of the most obvious uses for closures is in the few PHP functions that accept a callback function as a parameter. Closures, however, can be useful in any context where we need to encapsulate logic inside its own scope. One such example occurs when refactoring old code to help simplify it and make it more readable. Take the following example, which shows a logger being used while running some SQL queries.

Listing 13. Code logging SQL queries
$db = mysqli_connect("server","user","pass"); 
Logger::log('debug','database','Connected to database'); 
$db->query('insert into parts (part, description) values ('Hammer','Pounds nails'); 
Logger::log('debug','database','Insert Hammer into to parts table'); 
$db->query('insert into parts (part, description) values 
      ('Drill','Puts holes in wood');
Logger::log('debug','database','Insert Drill into to parts table'); 
$db->query('insert into parts (part, description) values ('Saw','Cuts wood'); 
Logger::log('debug','database','Insert Saw into to parts table');

One thing that sticks out in Listing 13 is how much repeating we are doing. Every call made to Logger::log() has the same first two arguments. To solve this, we can push that method call into a closure and make the calls against that closure, instead. The resulting code is shown below.

Listing 14. Refactored code logging SQL queries
$logdb = function ($string) { Logger::log('debug','database',$string); };
$db = mysqli_connect("server","user","pass"); 
$logdb('Connected to database'); 
$db->query('insert into parts (part, description) values ('Hammer','Pounds nails'); 
$logdb('Insert Hammer into to parts table'); 
$db->query('insert into parts (part, description) values 
       ('Drill','Puts holes in wood');
$logdb('Insert Drill into to parts table'); 
$db->query('insert into parts (part, description) values ('Saw','Cuts wood'); 
$logdb('Insert Saw into to parts table');

Not only have we made the code cleaner in appearance but we also made it easier to change the log level of the SQL queries log since we only need to make the change in one place now.


Summary

This article demonstrated how useful closures are as a functional programming construct within PHP V5.3 code. We discussed lambda functions and the advantages that closures have over them. Objects and closures get along very well, as we saw by the special handling of closures within object-oriented code. We saw how well we can use the reflection API to create dynamic closures, as well as introspect existing closures.

Resources

Learn

Get products and technologies

  • Innovate your next open source development project with IBM trial software, available for download or on DVD.
  • Download IBM product evaluation versions, and get your hands on application development tools and middleware products from DB2®, Lotus®, Rational®, Tivoli®, and WebSphere®.

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=356786
ArticleTitle=What's new in PHP V5.3, Part 2: Closures and lambda functions
publish-date=12092008