В чем разница между параметрами закрытия и ключевым словом «use»?

18

Это очень смутило меня, и я не могу найти ответа на этот вопрос. Ясное и простое разъяснение было бы приятным.

    
задан Seralize 21.05.2012 в 23:23
источник
  • Я думаю, что вы выбрали неправильный ответ –  Trix 03.06.2016 в 17:50

2 ответа

20

Закрытие - это функция, которая вычисляется в своей собственной среде, которая имеет одну или несколько связанных переменных, к которым можно получить доступ при вызове функции. Они происходят из мира функционального программирования, где есть ряд концепций в игре. Закрытия подобны лямбда-функциям, но более умны в том смысле, что они имеют возможность взаимодействовать с переменными из внешней среды, где определено замыкание.

Ключевое слово use () позволяет импортировать переменные извне среды функций внутри функции. Переменные, которые должны быть импортированы из внешней среды, указаны в предложении use определения функции закрытия. По умолчанию они передаются по значению. Итак, скажем, функция не имеет параметров, но вы не хотите использовать переменную, которую у вас уже есть.

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

Это полезно, когда вам нужно создать функцию, которая должна использоваться как обратный вызов где-то в другом месте, и может иметь только определенные параметры. Ключевое слово use () позволяет вам использовать другие переменные в дополнение к тем, которые вы передаете в качестве аргументов функции. Например, на примере php.net: Ссылка

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 должен иметь только два параметра, потому что array_walk будет только так много:

  

Как правило, funcname принимает два параметра. Параметр массива   значение является первым, а второй / индекс вторым.

Итак, что мы можем сделать? Мы вызываем use() для добавления других переменных, которые не являются областью $ callback, но в области среды, в которую она вызывается.

    
ответ дан Stanislav Palatnik 21.05.2012 в 23:33
источник
  • Это все еще не имеет смысла для меня. Как он отличается от $ clos = function ($ string) {echo $ string; } ;? –  Seralize 21.05.2012 в 23:41
  • @Seralize: Извините, обновил мой пример. В принципе, некоторые функции в PHP позволяют вызвать обратные вызовы (например, array_walk, array_map и т. Д., Которые имеют предопределенные параметры). В этих случаях вы можете вызвать use () для добавления других переменных, которые в противном случае не могли бы использоваться в обратном вызове. –  Stanislav Palatnik 21.05.2012 в 23:44
  • Это имеет смысл. Таким образом, ключевое слово use () - это просто способ импортировать переменные в замыкание без испорчения «потока параметров», поскольку параметры, которые не заданы, будут давать ошибку? –  Seralize 21.05.2012 в 23:46
  • @Seralize: Да. Это позволит вам добавить больше контекста к функции без изменения параметров. –  Stanislav Palatnik 21.05.2012 в 23:48
  • И то, что сказал @chris! –  Stanislav Palatnik 21.05.2012 в 23:58
Показать остальные комментарии
24

use statement фиксирует переменную в момент создания функции закрытия .

Регулярные аргументы функции захватывают значение , когда функция называется .

Обратите внимание, что я дифференцировал между variable и value там.

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

Если бы был способ проверить, «исходный код» функции $add5to , он будет выглядеть так:

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

Я думаю, вы могли бы сказать, что значение $leftNum было запомнено функцией закрытия.

Я хочу еще раз подчеркнуть, что use statement позволяет поддерживать reference переменной , а не только копию значения , что переменная в какой-то момент. Чтобы прояснить мою идею: подумайте о переменной как о небольшом поле, которое может содержать одно значение в любой момент времени, и это значение может быть изменено. И вы можете сделать другую переменную точкой для этого поля, чтобы вы могли обновить значение в поле или прочитать текущее значение в нем.

Обычно локальная переменная, созданная внутри функции, перестает существовать после возвращения функции. Но функция закрытия может поддерживать ссылку на эту переменную и приводить к тому, что локальная переменная будет работать даже после возвращения функции - и это истинная сила функций закрытия. Он позволяет вам подражать определенному поведению класса (переменные экземпляра) с помощью всего лишь небольшого количества кода.

Вот более продвинутый пример, который может занять некоторое глубокое мышление, чтобы понять тонкие детали поведения.

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.

Возможно, вы заметили, что я использовал оператор ссылки & в этом примере. Если вы еще не знакомы с ними, просто знайте, что, как известно, ссылки трудно понять. Хотя, надеюсь, этот пост в основном имеет смысл сам по себе.

    
ответ дан goat 21.05.2012 в 23:51
источник
  • Это хороший момент, который вы получили там. Мне потребовалось некоторое время, чтобы понять, как был вызван параметр $ rightnum, но теперь это имеет смысл. –  Seralize 22.05.2012 в 00:04
  • Я, некоторые из этих вещей действительно трудно понять, потому что есть так много точек косвенности и оценки. Я добавлю пояснения, которые, надеюсь, помогут. –  goat 22.05.2012 в 00:07
  • Этот ответ заслуживает того, чтобы быть принятым ответом –  Trix 03.06.2016 в 17:49