Closures coming in PHP 5.3 and that’s a Good Thing

February 20, 2009 – 5:48 pm Tags:

PHP 5.3 will be introducing closures to PHP. Closures, also known as anonymous functions, will allow you to declare functions “inline” and store them in variables. While the syntax may seem a bit weird compared to how it is in languages like JavaScript, closures will be a useful addition to the language. However, like reflection, it’s a feature that may not immediately show it’s usefulness…

Simple example

Let’s take a quick example of how you would define a closure:

$closure = function($param) { echo $param; };
 
//This one takes value of someVar and "stores" it in the closure's scope even if
//we later change the value of someVar outside it. We assume that $somerVar is defined before this
$closure2 = function($param) use ($someVar) { echo $param . ' ' . $someVar; };

Note that in earlier PHP versions, you can achieve a similar effect by using create_function. There are some problems with create_function, though, and using it is generally not recommended. Closures in 5.3 will work without the issues of create_function – not to mention have a much better syntax as you won’t have to escape your stuff in a string!

Next, let’s take a look at some ways you can immediately benefit from closures.

Use case: outputting HTML

In bigger applications it’s often typical to have more than one or two similar views of data. For example, you may want to have a paginated list of some kind of data stored in the database.

To preserve similar styling across your application, you should put code which outputs common elements such as these lists inside functions or classes so they are easy to reuse. However, there’s one problem here: what if you have some data, which requires a bit different formatting for the rows in the list? Maybe it needs an icon, or maybe you want to add some JavaScript code to run when you hover over the item.

You could add some code to the function, which allows the user to pass some parameters to it which change the way the rows are outputted, but this can lead to much clutter in the function itself, and when you need yet another slightly different list, you again need to modify the function.

Or, you could use a closure to provide a so-called “formatter” function to it!

function item_list(array $items, $formatter = null) {
  //create the default formatter
  if($formatter == null) {
    $formatter = function($row) {
      return '<p>' . $row . '</p>';
    };
  }
 
  $html = '<h2>Listing:</h2>';
  foreach($items as $item) {
    $html .= $formatter($item);
  }
 
  return $html;
}

So there we have an example list-creator function. It can take two arguments: the array of data to output, and an optional formatter.

//show a list of numbers using the default format:
echo item_list(array(1,2,3));
 
//let's show it in bold instead:
echo item_list(array(1,2,3), function($row) {
  return '<p><strong>' . $row . '</strong></p>';
});

Other uses

Closures could also be used as event handlers. If you’ve used JavaScript, chances are you’ve used something like window.onload = function() { … }.

Another good use is with functions such as array_map or usort: They take a function as an argument, which is then called once for each item in the array passed as the other argument. These functions aren’t always very complex, or maybe they aren’t used in more than one place, so you wouldn’t necessarily need to have them as separate functions.

For example, a recent question in #zftalk was about calling a specific method in each object in an array, and putting the result to another array:

$results = array();
array_map(function($row) use (&$results) { $results[] = $row->someMethod(); }, $someArray);

In this example, the use() is needed for the closure to be able to access $results. We also need to pass results as a reference, since the modifications we do inside the closure won’t otherwise affect it. What this code does could be achieved with a loop too.

Maybe a more typical example of a one-use function is with usort, which sorts an array by using a user defined sorting function:

$arr = array(2,1,3);
usort($arr, function($a, $b) { return $a < $b ? 1 : -1; });

Difference between use() and globals

You may wonder why do you need use() when you could use globals. It’s true that in a simple case using global $foo or use($foo) are pretty much the same, but there is a difference.

Imagine a case where you write a function, and there’s a local variable inside the function. You want to use this variable inside the closure.

In this case, we need to use the use clause. If we used global, it would attempt to look up the variable from the global scope. Even if there is no such variable available globally, it won’t use the local variable in the function. With use(), the local variable can be used inside the closure.

In closing

As you can see from the example, closures are quite useful if you just know how to use them. We even could modify the listing function to output some details from a class – we can pass it an array of class instances, and a function which calls a specific method of the class instead of just showing the $row variable itself. Too bad it’s probably going to take a while before PHP 5.3 is common enough to rely on this feature much.

Share this:
  1. 39 Responses to “Closures coming in PHP 5.3 and that’s a Good Thing”

  2. “Closures, also known as anonymous functions”
    wrong.
    Closures and anonymous functions are not the same thing/concept.

    By cirpo on Feb 20, 2009

  3. Thanks for making it clear. They are similar, but not exactly the same even though people do use both names for them.

    By Jani Hartikainen on Feb 20, 2009

  4. Is this purely usefull for functional style programming?

    The example provided seems to be served by the decorator oop pattern.

    DM

    By DangerMouse on Feb 21, 2009

  5. Hey Jani

    Nice article. Just to clarify is the “uses” clause not required in the array_map example?

    Since the closure accesses the $results var in the global scope?

    By phpslacker on Feb 21, 2009

  6. I was wondering if closure was acceptable as argument in array_map() and other from that kind ?

    By Radoslav Stankov on Feb 21, 2009

  7. phpslacker, I’m relatively sure it’s like that.

    Radoslav, I’ve been attempting to install 5.3′s beta version, but with no luck. The Windows one doesn’t seem to have the new features in it… Anyways, I would assume yes, as normally it would accept a callback, ie. function name or array for class methods.

    It wouldn’t be a very useful feature if it didn’t work like that :)

    By Jani Hartikainen on Feb 21, 2009

  8. This example won’t work for several reasons, and you don’t seem to understand how array_map works.

    $results = array();
    array_map(function($row) { $results[] = $row->someMethod(); }, $someArray);

    Your “item_list”-example has been possible to implement (nicely) in PHP since 4.0 when it got OOP through the decorator pattern or even earlier with a dynamic dispatch table (bit contrived though)

    You also seem to fail to understand how usort (or sorting in general?) works:

    usort($arr, function($a, $b) { return $a < $b; });

    will not produce correct results, since you need to return a number in the sequence [-1, 0, 1] for it to work properly.

    You also seem to mix up closures and anonymous function which ar not the same thing.

    Not to mention your “item_formater” example is horrible, mixing html and php like that.

    And, this code will not work either:

    $closure2 = function($param) uses ($someVar) { echo $param . ‘ ‘ . $someVar; };

    demonstrated by this example: $c = function() use($foo) { echo $foo; }; $c(); which will give you a E_NOTICE about an undefined variable.

    And last, as you say in closing that “losures are quite useful if you just know how to use them” is true – however you seem to lack any understanding of the concept and provide only examples that 1) don’t work properly, 2) generate runtime errors or 3) would be better implemented some way else.

    By Fredrik Holmström on Feb 23, 2009

  9. Hey!! Knock it off! Brow beating the guy for posting a slightly misguided intro to PHP’s closures/anonymous functions isn’t going to solve anything.

    It’s still PHP, after all!

    ::ducks!::

    By Anonymous Coward on Feb 23, 2009

  10. Fredrik, thanks for pointing out the stupid mistake in usort. I feel like a newbie because I wrote that sorting function totally wrong… that’s what you get for quickly writing a post and then declaring “YES! This post is now DONE!”

    I will correct the usort example in a bit. However, what comes for the rest of your critique, maybe you should post the “correct” way to do the list formatter thing with decorators or whatever you feel is better?

    I don’t exactly see why the way I did it is particularily bad – you do need to mix html + php at times, and I think it’s okay as long as it’s not something like sticking an SQL query there.

    Oh, and perhaps you should check your comment for mistakes too. I’m not going to start pointing them out, I’m sure you can see them yourself ;)

    By Jani Hartikainen on Feb 23, 2009

  11. Oh, and to Radoslav or anyone else who’s been wondering if the usort and array_map functions actually work with closures…

    The answer is yes, yes they do. I managed to get 5.3 running now, and it indeed does work like that. I updated one of the examples to reflect the way the use() clause works instead of what I had guessed earlier.

    By Jani Hartikainen on Feb 23, 2009

  12. Thank you, short and sweet read!

    By MJ on Feb 23, 2009

  13. This would be great in conjunction with PHPLinq, http://www.phplinq.net.

    By Maarten Balliauw on Feb 23, 2009

  14. Jani: You still fail to grasp array_map after my points, this code:

    $results = array();
    array_map(function($row) use (&$results) { $results[] = $row->someMethod(); }, $someArray);

    should be written as such:
    $results = array_map(function($row) { return $row->someMethod(); }, $someArray);

    Also, this (will sort edgecases weirdly):
    $arr = array(2,1,3);
    usort($arr, function($a, $b) { return $a < $b ? 1 : -1; });

    should be
    $arr = array(2,1,3)
    usort($arr, function($a, $b) { return $a $b) -1 : 0 ; });

    Also, this phrase: “It’s true that in a simple case using global $foo or use($foo) are pretty much the same, but there is a difference”. They are not even close to the same even in simple cases, and even while you can “use globals instead of use()” sometimes they shouldn’t be explained as “almost the same”.

    By Fredrik Holmström on Feb 23, 2009

  15. Ehm… wordpress slaughtered my code fr some reason… the usort should be (just the return statement)

    $a > $b ? 1 : ($a < $b ? -1 : 0);

    And I noticed that you’re original function will sort backwards in addition to not handle equality.

    By Fredrik Holmström on Feb 23, 2009

  16. Sigh, wordpress really is getting on my nerves, anyway… yeah there probably are a lot of spelling mistakes in my (three?) comments, but I’ve always had a “hard time” spelling, even in my native language (swedish), never had any problems with code though ;P

    By Fredrik Holmström on Feb 23, 2009

  17. The point with array_map was to demonstrate accessing the external variable, but I suppose it could’ve been done by using something else, since by returning the value you get pretty much the same effect w/ array_map.

    The usort function will handle equality just fine without the extra case, as it doesn’t matter if we sort equal numbers after or before their own equals.

    By Jani Hartikainen on Feb 23, 2009

  18. I think closures work better for the list example here than a decorator would. Using a decorator class would require much more code than a closure and the closure can be declared inline as he shows so if it’s a one time modification as that kind of things usually are it would be simpler too. KISS!

    By Big Mac on Feb 24, 2009

  19. No need for closure here, while they are great, it seems like syntax sugar for more compact non-reusable code, unless someone wants to create a jQuery like MVC framework for PHP:

    /**
    * This wraps entries around with tags
    */
    function p_formatter($row)
    {
    return “”.$row.”\n”;
    }

    /**
    * This wraps entries around with tags
    */
    function pstrong_formatter($row)
    {
    return “
    “.$row.”\n”;
    }

    function item_list(array $items, $formatter = null) {
    //create the default formatter
    if($formatter == null) {
    $formatter = “p_formatter”;
    }

    $html = “Listing:\n”;
    foreach($items as $item) {
    $html .= call_user_func_array($formatter, $item);
    }

    return $html;
    }

    echo item_list(array(1,2,3));
    echo “\n”;
    echo item_list(array(1,2,3), “pstrong_formatter”);

    By Fred on Feb 24, 2009

  20. $closure = function($param) { echo $param; }; is not a closure. It is a function named ‘closure’ that takes the argument ‘param’ and echoes it.

    A closure is a function that is evaluated in an environment containing one or more bound variables.

    For an understanding of closures read the Wikipedia entry on it:
    http://en.wikipedia.org/wiki/Closure_(computer_science)

    By takos on Mar 2, 2009

  21. The difference between an anonymous function and a closure is that a closure is a function that closes over one or more free variables, an anonymous function is a function created anonymously in a given language.

    Anonymous function:

    $v = 1;
    $f = function($x) { return $x+1; }

    Closure:

    $v = 1;
    $f = function($x) use ($v) { return $x+$v; }

    It’s probably best just to call them all ‘functions’, until you want to be specific, and then you say ‘anonymous function’ or ‘closure’.

    By Anonymous on Apr 29, 2009

  22. Nice read, however Im still confused where is the difference between use() and global??

    LOL, the usort() function could be:
    usort($arr, function($a, $b) { return $a – $b; });

    b/c there is no limitation to 1 or -1 only…

    By Orkan on May 16, 2009

  23. I think conflating anonymous functions and closures, even though they are technically different, comes from the fact that anonymous functions are first class values and that implementing first class functions without closures is not done anymore (see http://en.wikipedia.org/wiki/Funarg_problem)

    By zorg on Aug 9, 2009

  24. This is the first article when I googled about “PHP closure”. It clarify my concern on how PHP actually have closure. Without “use”, PHP doesn’t actually have closure, but just anonymous function.

    By Morgan Cheng on Sep 20, 2009

  25. cirpo, you’re wrong. He didn’t say they are the same, he said: “Closures, also KNOWN as anonymous functions”

    His statement is correct, they are both known by both names, however – you are correct in saying that they are technically different.

    Subtle but important difference.

    By Kirk Bushell on Jan 7, 2010

  26. Thanks

    By shaffy on Aug 12, 2010

  27. Your understanding of closure is incorrect. It is not “close” to being correct. There is no point in arguing that it’s correct, because it’s not correct. Please take down this article. It is extremely misleading and will teach people the wrong thing. You’re equating closures to first class functions which is wrong.

    Please read MDN’s closure explanation.

    By Steve on Jul 13, 2011

  28. Hi Steve

    Thank you for the constructive comment.

    I have no intention of removing this post. However, feel free to suggest how to change it (without removing it) to make it better.

    Also do note, that many people associate this construct with names “anonymous function” or “closure”, however wrong that may be. The point of this post was not to explain the difference between the two.

    By Jani Hartikainen on Jul 13, 2011

  29. I think that this post makes a good job for starting conversations about new techniques. I feel bad about people attacking the author instead of giving proper feedback how to make it better. In general, sorry about making someone as an example but Fredrik’s comments about “horrible” item_formatter that mixes HTML and PHP is fruitless and futile. This article is meant to be an example at algorithmic level of code instead of discussing how to do semantics, separating information from formatting and coding practices. People with a wide enough perspective (and concentrating on errors) should understand that. Keep it simple! Pointing errors in article is a different case :)

    I’ve actually written a similar example of mixing closures, array_mapping with recursive approach https://github.com/tovrleaf/php-code/blob/master/include/function.array-depth.php

    By Niko Kivelä on Jul 19, 2011

  30. @Niko such is the internet. Some people seem to pretty easily get knee-jerk reactions about things they don’t agree with.

    Interesting approach you take in that function though :D

    Also, I think we used to hang on the same IRC channel yeaaaars back. #scriptaajat or something along those lines?

    By Jani Hartikainen on Jul 21, 2011

  31. @Jani, haha – that might have be me! Good memory if you remember actual persons behind the nicks, I remember that channel really good even tho it was a reaaally long time ago. Small is the interwebz!

    By Niko Kivelä on Jul 21, 2011

  32. Hi,
    Thanks to this article, simple and well presented, i learned about php closures and use()

    By CoursesWeb on Mar 15, 2012

  1. 8 Trackback(s)

  2. Feb 25, 2009: Links XXXVI - Peter Kröner - Die Kunst des Machbaren
  3. Aug 8, 2009: PHP 5.3 kan nu v
  4. Jul 26, 2010: Gigahost Blog » PHP 5.3 now available in the Control Center!
  5. Oct 6, 2010: Как использовать разные версии PHP на одном хостинге | Школа программирования
  6. Feb 3, 2011: Que me dicen de CakePHP - Foros de CHW
  7. Feb 4, 2011: Algunos links interesantes « unreal4u's Personal Network
  8. Jul 14, 2011: http codeutopia net blog 2009 02 20 closures… « Joshy's microblog
  9. Sep 6, 2011: PHP and Closures « Desktop & Mobile

Post a Comment

You can use some HTML (a, em, strong, etc.). If you want to post code, use <pre lang="PHP">code here</pre> (you can replace PHP with the language you are posting)