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à:

object(Test)#1 (0) {
}

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

Log delle modifiche

Versione Descrizione
7.1.0 Le funzioni anonime non possono catturare superglobals, $this, o qualsiasi variabile con lo stesso nome di un parametro nel contesto in cui sono definite.

Note

Nota: È possibile usare func_num_args(), func_get_arg() e func_get_args() all'interno di una chiusura.