2012-05-21 2 views

risposta

19

Una chiusura è una funzione valutata nel proprio ambiente, che ha una o più variabili associate a cui è possibile accedere quando viene chiamata la funzione. Provengono dal mondo della programmazione funzionale, dove ci sono una serie di concetti in gioco. Le chiusure sono come funzioni lambda, ma più intelligenti nel senso che hanno la capacità di interagire con le variabili dall'ambiente esterno di dove è definita la chiusura.

La parola chiave use() consente di importare variabili dall'esterno dell'ambiente della funzione, all'interno della funzione. Le variabili da importare dall'ambiente esterno sono specificate nella clausola use della definizione della funzione di chiusura. Per impostazione predefinita, vengono passati per valore. Quindi diciamo che la funzione non ha parametri, ma non vuoi usare una variabile che hai già.

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

Ciò è utile quando è necessario creare una funzione di ciò che deve essere utilizzato come richiamata da qualche altra parte, e non può che hanno definito i parametri. La parola chiave use() consente di utilizzare altre variabili oltre a quelle passate come argomentazioni di funzioni. Per esempio sull'esempio 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 avere solo due parametri, perché array_walk consente solo di tanto:

Tipicamente, funcname assume due parametri. Il valore del parametro dell'array è il primo e il secondo chiave/indice.

Quindi cosa possiamo fare? Chiamiamo use() aggiungere altre variabili che non sono portata il $ di richiamata, ma nel campo di applicazione del dell'ambiente IT è chiamati a.

+0

Non ha ancora senso per me. Com'è diverso da '$ closure = function ($ string) {echo $ string; }; '? – Seralize

+1

@Seralize: mi dispiace, aggiornato il mio esempio. Fondamentalmente, alcune funzioni in PHP consentono i callback (come array_walk, array_map, ecc. Che hanno parametri predefiniti.) In questi casi, puoi chiamare use() per aggiungere altre variabili che altrimenti non sarebbe possibile usare in un callback. –

+0

Questo ha senso Quindi la parola chiave 'use()' è fondamentalmente solo un modo per importare variabili in una chiusura senza intaccare il "flusso di parametri", poiché i parametri che non sono impostati daranno un errore? – Seralize

24

Il use statement cattura la variabile al momento la funzione chiusura si crea.

Gli argomenti di funzioni regolari acquisiscono il valore quando la funzione è denominata.

Nota che ho differenziato tra variable e value lì.

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 

Se ci fosse un modo per ispezionare il, um, "codice sorgente" della funzione $add5to, sarebbe simile a questa:

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

Credo che si potrebbe po 'dire che il valore di $leftNum è stato ricordato dalla funzione di chiusura.

voglio sottolineare, inoltre, che il use statement consente di mantenere un reference ad una variabile , e non solo una copia del valoreche la variabile aveva ad un certo punto. Per chiarire la mia idea: pensa a una variabile come a una piccola scatola, che può contenere un singolo valore in qualsiasi istante nel tempo, e quel valore può essere cambiato.Inoltre, puoi fare in modo che un'altra variabile punti a quella casella, in modo che tu possa aggiornare il valore nella casella o leggere il valore corrente al suo interno.

Normalmente, una variabile locale creata all'interno di una funzione cessa di esistere dopo il ritorno della funzione. Ma una funzione di chiusura può mantenere un riferimento a quella variabile e far sì che la variabile locale vada avanti anche dopo il ritorno della funzione - e questo è il vero potere delle funzioni di chiusura. Ti permette di imitare certi comportamenti di una classe (variabili d'istanza), con solo un piccolo pezzetto di codice.

Ecco un esempio più avanzato, che potrebbe richiedere un po 'di riflessione per comprendere i dettagli del comportamento.

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. 

Avrete notato che ho usato il reference operator& in questo esempio. Se non hai ancora familiarità con loro, sappi solo che i riferimenti sono noti per essere difficili da capire. Anche se, spero che questo post abbia più senso da solo.

+0

Questo è un buon punto che hai ottenuto. Mi ci è voluto un po 'per capire come è stato chiamato il parametro '$ rightnum', ma ora ha senso. – Seralize

+0

Ya, alcune di queste cose sono davvero difficili da capire perché ci sono così tanti punti di riferimento e valutazione. Aggiungerò un chiarimento che, auspicabilmente, aiuta. – goat

+2

Questa risposta merita di essere la risposta accettata – Trix