Pergunta sobre anonymous-function, closures, php – Qual é a diferença entre os parâmetros de fechamento e a palavra-chave 'use'?

18

Isso me deixou muito confuso e não consigo encontrar uma resposta para essa pergunta. Um esclarecimento claro e simples seria bom.

Eu acho que você escolheu a resposta errada Pmpr

Sua resposta

2   a resposta
21

que possui uma ou mais variáveis ​​vinculadas que podem ser acessadas quando a função é chamada. Eles vêm do mundo da programação funcional, onde há vários conceitos em jogo. Fechamentos são como funções lambda, mas mais inteligentes no sentido de que eles têm a capacidade de interagir com variáveis ​​do ambiente externo de onde o fechamento é definido.

A palavra chave use () permite que você importe variáveis ​​de fora do ambiente de função, dentro da função. As variáveis ​​a serem importadas do ambiente externo são especificadas na cláusula use da definição da função de encerramento. Por padrão, eles são passados ​​por valor. Então, vamos dizer que a função não tem parâmetros, mas você não quer usar uma variável que você já tem.

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

Isso é útil quando você precisa criar uma função que deve ser usada como retorno de chamada em outro local e só pode ter parâmetros definidos. A palavra-chave use () permite usar outras variáveis ​​além daquelas que você passa como argumentos de função. Por exemplo, no exemplo do php.net: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 deve ter apenas dois parâmetros, porque array_walk só permitirá tanto assim:

Normalmente, funcname assume dois parâmetros. O valor do parâmetro da matriz é o primeiro e o segundo da chave / índice.

Então o que nós podemos fazer? Nós chamamosuse() para adicionar outras variáveis ​​que não são o escopo do $ callback, mas no escopo do ambiente está sendo chamado.

De certa forma, parece inútil, mas em outro sempre haverá momentos em que essas pequenas coisas podem ajudar a resolver um problema. Obrigado por esclarecer! Seralize
@Seralize: é o objetivo de umfecho. Não tem nada a ver com "fluxo de parâmetro" ou qualquer outra coisa. O que você deu depois é uma função que sempre mostra seu argumento, o que não é interessante. Com a expressão anterior, podemos fazer uma função que imprima "foo", ou uma função que imprima "barra" ou qualquer outra coisa; e fazemos isso sem realmente escrever diferentes funções; essa linha de código, toda vez que é executada, criará uma função com novo comportamento (dependendo do valor da variável capturada) - como se você tivesse escrito manualmente funções separadas para elas. Essa é a diferença. newacct
Isso faz sentido. Então ouse() A palavra-chave é basicamente apenas uma maneira de importar variáveis ​​para um fechamento sem atrapalhar o "fluxo de parâmetros", já que os parâmetros que não estão definidos darão um erro? Seralize
Também o que @chris mencionou! Stanislav Palatnik
25

use statement captura variável n mment em que funçã de fechament é criada.

Arguments regulares de funçã capturamvalr quand a funçã échamad.

Nte que eu diferenciei entrevariable evalue lá.

functin makeAnAdder($leftNum) {
    // Ntice that *each time* this makeAnAdder functin gets called, we 
    // create and then return a brand new clsure functin.
    $clsureFunc = functin($rightNum) use ($leftNum) {
        return $leftNum + $rightNum;
    };

    return $clsureFunc;
}

$add5t = makeAnAdder(5);
$add7t = makeAnAdder(7);

ech $add5t(10); // 15
ech $add7t(1); // 8

Se huvesse uma maneira de inspecinar &qut;códig fnte&qut; d$add5t funçã, ficaria assim:

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

Eu ach que vcê pderia dizer valr de$leftNum fi lembrad pela funçã de fechament.

Quer enfatizar ainda mais que use statement permite que vcê mantenha umreference para umvariável, e nã apenas uma cópia dvalr que a variável teve em algum mment. Para esclarecer minha ideia: pense em uma variável cm send uma pequena caixa, que pde cnter um valr únic a qualquer instante, e esse valr pde ser alterad. E vcê pde fazer utra variável apntar para essa caixa, para que vcê pssa atualizar valr na caixa u ler valr atual nela.

Nrmalmente, uma variável lcal que é criada dentr de uma funçã deixa de existir após a funçã retrnar. Mas, uma funçã de fechament pde manter uma referência a essa variável e fazer cm que a variável lcal permaneça ativa mesm depis que a funçã retrnar - e esse é verdadeir pder das funções de fechament. Ele permite imitar certs cmprtaments de uma classe (variáveis ​​de instância), cm apenas um pequen códig.

Aqui está um exempl mais avançad, que pde levar algum pensament prfund para entender s detalhes d cmprtament.

functin makeBankAccunt() {
    // Each time this makeBankAccunt func is called, a new, ttally
    // independent lcal variable named $balance is created.
    $balance = 0;

    // Als, n each call we create 2 new clsure functins, $mdifyBalance, and $getBalance
    // which will hld a reference t the $balance variable even after makeBankAccunt returns.
    $mdifyBalance = functin($amunt) use (&$balance) {
        $balance += $amunt;
    };

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

    // return bth clsure functins.
    return [&aps;mdifyBalance&aps; => $mdifyBalance, &aps;getBalance&aps; => $getBalance];
}

// Let&aps;s prve that bank1 wrks by adding 5 t the balance by using the first
// functin, then using the ther functin t get the balance
// frm the same internal variable.
$bank1 = makeBankAccunt();
$bank1[&aps;mdifyBalance&aps;](5);
ech $bank1[&aps;getBalance&aps;](); // 5 - it wrks.

// Nw let&aps;s make anther bank t prve that it has it&aps;s wn independent internal $balance variable.
$bank2 = makeBankAccunt();
$bank2[&aps;mdifyBalance&aps;](10);
ech $bank2[&aps;getBalance&aps;](); // 10 - as expected. It wuld have printed 15 if bank2 shared a variable with bank1.

// Let&aps;s test bank1 ne mre time t be sure that bank2 didn&aps;t mess with it.
ech $bank1[&aps;getBalance&aps;](); // 5 - still 5, as expected.

Vcê deve ter ntad que eu useiperadr de referência & neste exempl. Se vcê ainda nã está familiarizad cm eles, saiba que as referências sã difíceis de entender. Embra, eu esper que este pst faça sentid pr si só.

Esta resposta merece ser a resposta aceita Pmpr
Esse é um bom ponto que você chegou lá. Levei um tempo para entender como$rightnum parâmetro foi chamado, mas faz sentido agora. Seralize
Ya, algumas dessas coisas são realmente difíceis de entender porque há muitos pontos de indireção e avaliação. Eu adicionarei um esclarecimento que ajude. goat

Perguntas relacionadas