Funzioni anonime
Le funzioni anonime, chiamate anche chiusure o closures
, permettono la
creazione di funzioni che non possiedono un nome. Sono molto utili come
valore dei parametri callable,
ma hanno molti altri utilizzi.
Le funzioni anonime sono implementate usando la classe
Closure.
Example #1 Esempio di funzione anonima
<?php
echo preg_replace_callback('~-([a-z])~', function ($match) {
return strtoupper($match[1]);
}, 'hello-world');
// stampa helloWorld
?>
Le chiusure possono essere usate anche come valore di una variabile; il PHP converte
automaticamente queste espressioni in istanze della
classe interna Closure. L'assegnazione di una chiusura a
una variabile usa la stessa sintassi di un qualsiasi altro assegnazione, incluso il
punto e virgola alla fine:
Example #2 Esempio di assegnazione di funzione anonima
<?php
$greet = function($name)
{
printf("Hello %s\r\n", $name);
};
$greet('World');
$greet('PHP');
?>
Le chiusure possono anche ereditare le variabili dal contesto del genitore. Ognuna di queste
variabili deve essere passata al costrutto del linguaggio use
.
A partire da PHP 7.1, queste variabili non devono includere superglobals,
$this, o variabili con lo stesso nome di un parametro.
Una dichiarazione del tipo di ritorno della funzione deve essere posta
dopo la clausola use
.
Example #3 Ereditare variabili dal contesto del genitore
<?php
$message = 'hello';
// Nessun "use"
$example = function () {
var_dump($message);
};
$example();
// Eredita $message
$example = function () use ($message) {
var_dump($message);
};
$example();
// Il valore della variabile ereditata è da quando la funzione
// è definita, non quando chiamata
$message = 'world';
$example();
// Resetta il messaggio
$message = 'hello';
// Eredita per riferimento
$example = function () use (&$message) {
var_dump($message);
};
$example();
// Il valore cambiato nel contesto del genitore
// è riflesso all'interno della chiamata della funzione
$message = 'world';
$example();
// Le closure possono anche accettare argomenti regolari
$example = function ($arg) use ($message) {
var_dump($arg . ' ' . $message);
};
$example("hello");
// La dichiarazione del tipo di ritorno viene dopo la clausola use
$example = function () use ($message): string {
return "hello $message";
};
var_dump($example());
?>
Il precedente esempio visualizzerà
qualcosa simile a:
Notice: Undefined variable: message in /example.php on line 6
NULL
string(5) "hello"
string(5) "hello"
string(5) "hello"
string(5) "world"
string(11) "hello world"
string(11) "hello world"
A partire da PHP 8.0.0, l'elenco delle variabili ereditate dallo scope può includere una virgola
finale, che verrà ignorata.
Ereditare le variabili dall'ambito genitore non
è la stessa cosa che usare variabili globali.
Le variabili globali esistono nell'ambito globale, che è lo stesso, indipendentemente
da quale funzione è in esecuzione. L'ambito genitore di una chiusura è la
funzione nella quale la chiusura è stata dichiarata (non necessariamente la funzione da
cui è stata chiamata). Si veda l'esempio seguente:
Example #4 Chiusure e ambiti di visibilità
<?php
// Un semplice paniere che contiene una lista di prodotti aggiunti
// e la quantità di ciascun prodotto. Include un metodo che
// calcola il prezzo totale degli articoli nel paniere utilizzando
// una chiusura come callback.
class Cart
{
const PRICE_BUTTER = 1.00;
const PRICE_MILK = 3.00;
const PRICE_EGGS = 6.95;
protected $products = array();
public function add($product, $quantity)
{
$this->products[$product] = $quantity;
}
public function getQuantity($product)
{
return isset($this->products[$product]) ? $this->products[$product] :
FALSE;
}
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);
}
}
$my_cart = new Cart;
// Aggiunta di un elemento nel paniere
$my_cart->add('butter', 1);
$my_cart->add('milk', 3);
$my_cart->add('eggs', 6);
// Stampa del totale con una tassa aggiuntiva del 5%.
print $my_cart->getTotal(0.05) . "\n";
// The result is 54.29
?>
Example #5 Binding automatico di $this
<?php
class Test
{
public function testing()
{
return function() {
var_dump($this);
};
}
}
$object = new Test;
$function = $object->testing();
$function();
?>
Il precedente esempio visualizzerà:
Quando dichiarata all'interno del contesto di una classe, la classe corrente è
automaticamente legata ad essa, rendendo $this
disponibile
all'interno dello scope di una funzione. Se questo binding automatico della classe
corrente non è voluto, allora
possono essere invece usate le
funzioni anonime statiche.
Funzioni anonime statiche
Le funzioni anonime possono essere dichiarate staticamente. Questo
impedisce loro di avere la classe corrente automaticamente legata ad
esse. Gli oggetti possono anche non essere legati a loro in fase di esecuzione.
Example #6 Tentativo di utilizzo di $this
all'interno di una funzione anonima statica
<?php
class Foo
{
function __construct()
{
$func = static function() {
var_dump($this);
};
$func();
}
};
new Foo();
?>
Il precedente esempio visualizzerà:
Notice: Undefined variable: this in %s on line %d
NULL
Example #7 Tentativo di legare un oggetto ad una funzione anonima statica
<?php
$func = static function() {
// function body
};
$func = $func->bindTo(new StdClass);
$func();
?>
Il precedente esempio visualizzerà:
Warning: Cannot bind an instance to a static closure in %s on line %d