Skip to main content

Closures in PHP… what, precisely, are they and when would you need to use them?



So I'm programming along in a nice, up to date, object oriented fashion. I regularly make use of the various aspects of OO programming that PHP implements but I am wondering when might I need to use closures. Any experts out there that can shed some light on when it would be useful to implement closures?




Comments

  1. When you will need a function in the future which performs a task that you have decided upon now.

    For example, if you read a config file and one of the parameters tells you that the hash_method for your algorithm is multiply rather than square, you can create a closure that will be used wherever you need to hash something.

    The closure can be created in (for example) config_parser(); it creates a function called do_hash_method() using variables local to config_parser() (from the config file). Whenever do_hash_method() is called, it has access to variables in the local scope ofconfig_parser() even though it's not being called in that scope.

    A hopefully good hypothetical example:

    function config_parser()
    {
    // Do some code here
    // $hash_method is in config_parser() local scope
    $hash_method = 'multiply';

    if ($hashing_enabled)
    {
    function do_hash_method($var)
    {
    // $hash_method is from the parent's local scope
    if ($hash_method == 'multiply')
    return $var * $var;
    else
    return $var ^ $var;
    }
    }
    }


    function hashme($val)
    {
    // do_hash_method still knows about $hash_method
    // even though it's not in the local scope anymore
    $val = do_hash_method($val)
    }

    ReplyDelete
  2. PHP will support closures natively in 5.3. A closure is good when you want a local function that's only used for some small, specific purpose. The RFC for closures givea a good example:

    function replace_spaces ($text) {
    $replacement = function ($matches) {
    return str_replace ($matches[1], ' ', ' ').' ';
    };
    return preg_replace_callback ('/( +) /', $replacement, $text);
    }


    This lets you define the "replacement" function locally inside replace_spaces(), so that it's not 1) cluttering up the global namespace, and 2) making people three years down the line wonder why there's a function defined globally that's only used inside one other function. It keeps things organized. Notice how the function itself has no name, it simply is defined and assigned as a reference to $replacement.

    But remember, you have to wait for PHP 5.3 :)

    ReplyDelete
  3. Apart from the technical details, closures are a fundamental pre-requisite for a programming style known as function oriented programming. A closure is roughly used for the same thing as you use an object for in object oriented programming; It binds data (variables) together with some code (a function), that you can then pass around to somewhere else. As such, they impact on the way that you write programs or - if you don't change the way you write your programs - they don't have any impact at all.

    In the context of PHP, they are a little odd, since PHP already is heavy on the class based, object oriented paradigm, as well as the older procedural one. Usually, languages that have closures, has full lexical scope. To maintain backwards compatibility, PHP is not going to get this, so that means that closures are going to be a little different here, than in other languages. I think we have yet to see exactly how they will be used.

    ReplyDelete
  4. @john Boker - they are coming, I believe, in PHP 5.3

    Here's a good link about them, explaining some of their usefulness http://wiki.php.net/rfc/closures

    ReplyDelete
  5. I like the context provided by troelskn's post. When I want to do something like Dan Udey's example in PHP, i use the OO Strategy Pattern. In my opinion, this is much better than introducing a new global function whose behavior is determined at runtime.

    http://en.wikipedia.org/wiki/Strategy_pattern

    You can also call functions and methods using a variable holding the method name in PHP, which is great. so another take on Dan's example would be something like this:

    class ConfigurableEncoder{
    private $algorithm = 'multiply'; //default is multiply

    public function encode($x){
    return call_user_func(array($this,$this->algorithm),$x);
    }

    public function multiply($x){
    return $x * 5;
    }

    public function add($x){
    return $x + 5;
    }

    public function setAlgorithm($algName){
    switch(strtolower($algName)){
    case 'add':
    $this->algorithm = 'add';
    break;
    case 'multiply': //fall through
    default: //default is multiply
    $this->algorithm = 'multiply';
    break;
    }
    }
    }

    $raw = 5;
    $encoder = new ConfigurableEncoder(); // set to multiply
    echo "raw: $raw\n"; // 5
    echo "multiply: " . $encoder->encode($raw) . "\n"; // 25
    $encoder->setAlgorithm('add');
    echo "add: " . $encoder->encode($raw) . "\n"; // 10


    of course, if you want it to be available everywhere, you could just make everything static...

    ReplyDelete
  6. I dont think php supports closures without without a helper class. that said, there are a few closure implementations for php. this one http://blinkinglights.org/php/Closure.php give a good explanation of what they are and where they might be useful.

    ReplyDelete

Post a Comment

Popular posts from this blog

[韓日関係] 首相含む大幅な内閣改造の可能性…早ければ来月10日ごろ=韓国

div not scrolling properly with slimScroll plugin

I am using the slimScroll plugin for jQuery by Piotr Rochala Which is a great plugin for nice scrollbars on most browsers but I am stuck because I am using it for a chat box and whenever the user appends new text to the boxit does scroll using the .scrollTop() method however the plugin's scrollbar doesnt scroll with it and when the user wants to look though the chat history it will start scrolling from near the top. I have made a quick demo of my situation http://jsfiddle.net/DY9CT/2/ Does anyone know how to solve this problem?

Why does this javascript based printing cause Safari to refresh the page?

The page I am working on has a javascript function executed to print parts of the page. For some reason, printing in Safari, causes the window to somehow update. I say somehow, because it does not really refresh as in reload the page, but rather it starts the "rendering" of the page from start, i.e. scroll to top, flash animations start from 0, and so forth. The effect is reproduced by this fiddle: http://jsfiddle.net/fYmnB/ Clicking the print button and finishing or cancelling a print in Safari causes the screen to "go white" for a sec, which in my real website manifests itself as something "like" a reload. While running print button with, let's say, Firefox, just opens and closes the print dialogue without affecting the fiddle page in any way. Is there something with my way of calling the browsers print method that causes this, or how can it be explained - and preferably, avoided? P.S.: On my real site the same occurs with Chrome. In the ex