PHP 5.3 and Closures

I’m fairly excited because as of only a week or so ago I found the closures rfc, and not only did I find that the rfc has a working patch, apparently it’s already in PHP 5.3.

You see, apparently it’s not good enough that we get name spaces and late static binding, oh no, we get closures too!

I downloaded the Win32 snapshot from PHP snapshots page and indeed, closure support was included.

$closure = function ($args) use ($global) { /*Body*/ };

According to the rfc, one must manually define external variables used within a function, however in my own tests you can still use the global keyword. The difference between the two is the use statement preserves the value of $global at creation and the global keyword would work as you would expect it to with a normal function. For example:

$global = "Global Variable";

$closureUse = function ($arg) use ($global) { echo $global . " - " . $arg; };
$closureGlobal = function ($arg) { global $global; echo $global . " - " . $arg; };

echo "Basic Closure Testsn";
echo "-------------------nn";

echo "$closureUse('test'): ";
$closureUse('test');
echo "n";

echo "$closureGlobal('test'): ";
$closureGlobal('test');
echo "n";

echo "n";
echo "Global Closure Testsn";
echo "--------------------nn";

$global = "Global Variable (Changed)";

echo "$closureUse('test') (changed $global): ";
$closureUse('test');
echo "n";

echo "$closureGlobal('test') (changed $global): ";
$closureGlobal('test');
echo "n";

Would output:

Basic Closure Tests
-------------------

$closureUse('test'): Global Variable - test
$closureGlobal('test'): Global Variable - test

Global Closure Tests
--------------------

$closureUse('test') (changed $global): Global Variable - test
$closureGlobal('test') (changed $global): Global Variable (Changed) - test

You can, as well, return references with a closure by putting the & between the function keyword and the parenthesis.

$closureReturnsReference = function & ($args) use ($global) { /*Body*/ };

Just one of many shiny fancy things to look forward to in PHP 5.3.

Edit 7/23/2008:

I should mention to the people that trashed my examples on reddit, I’m sorry for assuming you knew what closures were and the the real world uses of them. I will try to refrain from giving a concise example of how a new language feature interacts with existing features and conventions, especially in PHP where things are a bit disorganized.

Comments 10

  1. David Dashifen Kees wrote:

    You know … we probably shouldn’t get this excited over programming language enhancements….

    Posted 21 Jul 2008 at 6:34 pm
  2. Daniel Cousineau wrote:

    Nonsense!

    Posted 21 Jul 2008 at 6:54 pm
  3. sapphirecat wrote:

    I just messed around with it a bit, and discovered this:

    $g2 = 2;
    $closureReadOnly = function () use ($g2) { echo ++$g2 . "\n"; };
    // Note that we take a *reference* to $g2 this time:
    $closureReadWrite = function () use (&$g2) { echo ++$g2 . "\n"; };
    
    $closureReadOnly(); // 3
    $closureReadOnly(); // 3, but would be 4 in JavaScript
    
    $closureReadWrite(); // 3
    $closureReadWrite(); // 4
    echo $g2 . "\n"; // 4
    $closureReadOnly(); // 3 (still has private copy)

    So they seem to have taken the usual half-broken approach: you can have read-only closures which are immune to changes to a global variable, or you can have read-write closures which remember changes, but those changes leak back into the global variable.

    Fortunately, there’s a simple workaround. If you create a read-write closure inside a function, then the function prevents changes from leaking into global scope. And thankfully, multiple invocations of the function do properly create multiple copies of the variable, so calling a function to generate several closures does create fully independent closures.

    Here’s a somewhat practical example:

    function tableRowColors(array $colors) {
      $i = 0;
      $max = count($colors);
      // ensure contiguous, integral keys
      $colors = array_values($colors);
      $nextColor = function () use (&$i, $max) {
        $color = $colors[$i];
        $i = ($i + 1) % $max;
        return $color;
      };
      return $nextColor;
    }
    
    $t1_nextColor = tableRowColors(array('#cfc', '#aea'));
    $t2_nextColor = tableRowColors(array('#fff', '#eee', '#ddd', '#ccc'));

    Now each time you call $t1_nextColor() or $t2_nextColor(), they’ll generate the next color in their respective sequence.

    Posted 21 Jul 2008 at 8:03 pm
  4. Venkman wrote:

    sapphirecat, the problem is just what is a closure.

    It’s called closure because, well, it’s closed. In the examples where some function just accesses some global variable, you don’t really have a closure. The global is in scope always (naturally, that’s why it’s global).

    Your second example _is_ precisely a closure. The scope is closed to the rest of the world, but it’s still referenced and available to the returned function.

    So, the problem is not that “the closure leaks to the global variable”. That’s just normal behavior because it’s not a closure.

    Posted 22 Jul 2008 at 12:26 am
  5. php wrote:

    Well I’m really excited. Now I am waiting for goto() function to be implemented.. that will also be great

    Posted 22 Jul 2008 at 5:26 pm
  6. Michael Kimsal wrote:

    I’m really curious if these will be ‘abused’ or ‘overused’ or ‘misused’ (by multiple different conflicting defintions!). Having used closures in Groovy where they are very central to the language, I still have a hard time seeing too many use cases in PHP right now. We’ll wait and see how the community adapts to this new aspect of the language!

    Posted 23 Jul 2008 at 2:25 pm
  7. Crystaldyn wrote:

    These are read-only closures by default. You can make them read-write by using the &-sign in the use() list, but if you’re using a global variable, you just get a normal reference to that variable. In that case, it’s not closure at all. Fortunately, it does work sanely if you define the lambda in a function or method. Then you’ll get a real, private, read-write variable. I hope that’s clear. I’m excited. I can’t use it in paid work yet, but lo! That joyous day is coming.

    Posted 23 Jul 2008 at 2:34 pm
  8. Brad Miller wrote:

    Wake me when the rest of Lisp is implemented in PHP.

    Posted 25 Jul 2008 at 7:57 am
  9. deadimp wrote:

    This is a lot better than using ‘create_function’ to make anonymous functions. Woot!

    Posted 24 Aug 2008 at 7:47 pm
  10. Colleen Dick wrote:

    The use variable does not need to have global scope, and in fact it is probably bad programming to have it so. It can be a local var inside a function that declares a lambda. And the other people are right, using the global keyword inside the function makes it totally NOT a closure cuz a closure is, well, closed, by definition.

    Posted 11 Mar 2010 at 1:36 am

Trackbacks & Pingbacks 12

  1. From Closures en PHP 5.3 | WEBDEV on 22 Jul 2008 at 12:49 am

    [...] Me quedo sorprendido al enterarme de que, probablemente, las “closures” serán implementadas en PHP 5.3. [...]

  2. From PHP is getting closures! | Suburban Chicago PHP on 22 Jul 2008 at 6:51 am

    [...] I’ve seen very little from PHP that got me excited lately.  So, imagine how excited I am to hear that closures are coming to PHP 5.3! [...]

  3. From roScripts - Webmaster resources and websites on 22 Jul 2008 at 10:15 am

    Tower Of Power » Blog Archive » PHP 5.3 and Closures…

    Tower Of Power » Blog Archive » PHP 5.3 and Closures…

  4. From » Anonyme Funktionen in PHP 5.3 Flusensieb on 23 Jul 2008 at 12:50 am

    [...] hats bisher schon gegeben und zwar mittels create_function. Ab 5.3 wirds in PHP auch sogenannte Closures geben. Das Ganze schaut aus wie die anonymen Funktionen in [...]

  5. From dahlia's me2DAY on 23 Jul 2008 at 1:41 am

    홍민희의 생각…

    PHP 5.3 and Closures / 네임스페이스와 함께 드디어 클로져도 5.3에서 구현되는군요. Phunctional은 더이상 개발하지 않아도 될 것 같습니다….

  6. From Anonymous (Lambda) functions in php 5.3 and above. on 23 Jul 2008 at 6:37 am

    [...] found a post by Daniel Cousineau on php5.3’s closures that lead me to the closures [...]

  7. From adraðblog » Blog Archive » PHP is now less crappy than Java on 23 Jul 2008 at 1:44 pm

    [...] And by “is less crappy than Java”, I mean “has closures”. [...]

  8. From Linkdump: Matematika za programere, PHP 5.3 novosti… by Nikola Plejić on 24 Jul 2008 at 1:39 am

    [...] PHP 5.3 and Closures [...]

  9. From Lambda Functions in PHP | Bao's blog on 24 Jul 2008 at 4:27 am

    [...] : 1,2 Programming ~ Tags: closure, lambda, [...]

  10. From PHP 5.3 Improvements » EricByers.com on 07 Sep 2008 at 12:33 am

    [...] Lambda functions and Closures [...]

  11. From Recent Links Tagged With "php" - JabberTags on 29 Sep 2008 at 12:04 am

    [...] public links >> php PHP 5.3 and Closures Saved by ckendall on Sat 27-9-2008 Using actions in your WordPress themes Saved by thedpshow on [...]

  12. From Anonymous Functions. on 27 Dec 2008 at 4:35 am

    [...] Darüber hinaus! PHP 5.3 kommt auch mit ähnlichen Features. [...]

Post a Comment

Your email is never published nor shared. Required fields are marked *