Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What's the difference between closure parameters and the 'use' keyword?

This has got me very confused and I can't seem to find an answer to this question. A clear and simple clarification would be nice.

like image 567
Seralize Avatar asked May 21 '12 21:05

Seralize


People also ask

What is the difference between closure and function?

Difference between Function and ClosureFunction is declared using func keyword whereas Closure doesn't have func keyword. Function has always name but Closure doesn't have. Function doesn't have in keyword but closure has in the keyword.

What is a closure in PHP and why does it use the use identifier?

A closure is a separate namespace, normally, you can not access variables defined outside of this namespace. There comes the use keyword: use allows you to access (use) the succeeding variables inside the closure. use is early binding. That means the variable values are COPIED upon DEFINING the closure.

What is the use of closure in Swift?

Closures in Swift are similar to blocks in C and Objective-C and to lambdas in other programming languages. Closures can capture and store references to any constants and variables from the context in which they're defined. This is known as closing over those constants and variables.

What is the use of closure?

A closure is the combination of a function bundled together (enclosed) with references to its surrounding state (the lexical environment). In other words, a closure gives you access to an outer function's scope from an inner function.


2 Answers

The use statement captures the variable at the time the closure function is created.

Regular function arguments capture the value when the function is called.

Note that I differentiated between variable and value there.

function makeAnAdder($leftNum) {
    // Notice that *each time* this makeAnAdder function gets called, we 
    // create and then return a brand new closure function.
    $closureFunc = function($rightNum) use ($leftNum) {
        return $leftNum + $rightNum;
    };

    return $closureFunc;
}

$add5to = makeAnAdder(5);
$add7to = makeAnAdder(7);

echo $add5to(10); // 15
echo $add7to(1); // 8

If there were a way to inspect the, um, "source code" of the $add5to function, it would look like this:

function($rightNum) {
    return 5 + $rightNum;
}

I guess you could kinda say the value of $leftNum got remembered by the closure function.

I want to further emphasize that the use statement allows you to maintain a reference to a variable, and not just a copy of the value that the variable had at some point. To clarify my idea: think of a variable as being a little box, which can contain a single value at any instant in time, and that value can be changed. And, you can make another variable point to that box, so that you can update the value in the box, or read the current value in it.

Normally, a local variable that is created within a function ceases to exist after the function returns. But, a closure function can maintain a reference to that variable, and cause that local variable to live on even after the function returns - and this is the true power of closure functions. It lets you mimic certain behaviors of a class (instance variables), with just a tiny bit of code.

Here's a more advanced example, that might take some deep thinking to understand the fine details of the behavior.

function makeBankAccount() {
    // Each time this makeBankAccount func is called, a new, totally
    // independent local variable named $balance is created.
    $balance = 0;

    // Also, on each call we create 2 new closure functions, $modifyBalance, and $getBalance
    // which will hold a reference to the $balance variable even after makeBankAccount returns.
    $modifyBalance = function($amount) use (&$balance) {
        $balance += $amount;
    };

    $getBalance = function() use (&$balance) {
        return $balance;
    };

    // return both closure functions.
    return ['modifyBalance' => $modifyBalance, 'getBalance' => $getBalance];
}

// Let's prove that bank1 works by adding 5 to the balance by using the first
// function, then using the other function to get the balance
// from the same internal variable.
$bank1 = makeBankAccount();
$bank1['modifyBalance'](5);
echo $bank1['getBalance'](); // 5 - it works.

// Now let's make another bank to prove that it has it's own independent internal $balance variable.
$bank2 = makeBankAccount();
$bank2['modifyBalance'](10);
echo $bank2['getBalance'](); // 10 - as expected. It would have printed 15 if bank2 shared a variable with bank1.

// Let's test bank1 one more time to be sure that bank2 didn't mess with it.
echo $bank1['getBalance'](); // 5 - still 5, as expected.

You may have noticed I used the reference operator & in this example. If you're not yet familiar with them yet, just know that References are known to be hard to understand. Although, I hope this post mostly makes sense by itself.

like image 66
goat Avatar answered Oct 22 '22 06:10

goat


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.

The use() keyword let's you import variables from outside the function environment, inside the function. 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. So let's say the function has no parameters, but you wan't it to use a variable you already have.

$string = "Hello World!";
$closure = function() use ($string) { echo $string; };

This is useful when you need to create a function what must be used as callback somewhere else, and can only have defined parameters. The use() keyword let's you use other variables in addition to the ones you pass as function arguements. For example on the php.net example: http://php.net/manual/en/functions.anonymous.php

public function getTotal($tax)
    {
        $total = 0.00;

        $callback =
            function ($quantity, $product) use ($tax, &$total)
            {
                $pricePerItem = constant(__CLASS__ . "::PRICE_" .
                    strtoupper($product));
                $total += ($pricePerItem * $quantity) * ($tax + 1.0);
            };

        array_walk($this->products, $callback);
        return round($total, 2);
    }

$callback must only have two parameters, because array_walk will only allow that much:

Typically, funcname takes on two parameters. The array parameter's value being the first, and the key/index second.

So what can we do? We call use() to add other variables that are not the $callback's scope, but in scope of the environment it is being called in.

like image 43
stan Avatar answered Oct 22 '22 07:10

stan