Funzioni anonime in PHP

Funzioni anonime in PHP: cosa sono, sintassi e casi d'uso.

A partire da PHP 5.3, è possibile creare funzioni anonime, conosciute anche con il nome di closure. Questa funzionalità di PHP non viene usata spesso, ma può tornare utile in diverse occasioni, tipo nel caso dovessimo passare una funzione come argomento di un'altra funzione.

Prima di addentrarci negli esempi pratici, vediamo innanzitutto cos'è una funzione anonima.

Cos'è una funzione anonima

Da Wikipedia:

In programmazione informatica, una funzione anonima o funzione lambda è una funzione definita, e possibilmente chiamata, senza essere legata ad un identificatore. Le funzioni anonime sono utili per passare come argomento una funzione di ordine superiore e si trovano in linguaggi che supportano funzioni di prima classe come Haskell.

Da questa definizione possiamo subito intuire che una funzione anonima, come dice il nome stesso, è una funzione senza un nome.

Sintassi

Nella guida precedente abbiamo visto come definire una funzione normale

<?php
function myFunction() {
    // codice
}

e come chiamarla per utilizzarla nei nostri programmi

<?php
myFunction();

Le funzioni anonime sono del tutto simili alle funzioni normali, in quanto possono contenere del codice, accettano argomenti e restituiscono dei valori. La differenza più evidente è nel nome, infatti una funzione anonima è una funzione senza un nome. Il seguente codice mostra un esempio di utilizzo:

<?php
function ($param1, $param2) {
    //codice
};

Possiamo notare due sostanziali differenze con le funzioni normali:

  • La funzione non ha un nome, infatti dopo la keyword function ci sono direttamente le parentesi.
  • Dopo la definizione della funzione, c'è un punto e virgola (;). Questo indica che le funzioni anonime sono espressioni, mentre le funzioni normali sono costrutti del linguaggio.

Casi d'uso

Abbiamo visto la sintassi delle funzioni anonime, ma non sappiamo ancora come utilizzarle all'interno dei nostri programmi. Come è possibile chiamare una funzione di cui non si conosce il nome? Vediamo tre casi di utilizzo con esempi di codice. PHP ci consente di:

  1. Assegnare una funzione anonima a una variabile, quindi chiamare la funzione utilizzando il nome della variabile.
  2. Usare una funzione anonima come funzione di callback, ossia come parametro di un'altra funzione.
  3. Utilizzare la funzione anonima per creare closure.

Analizziamo i tre casi con degli esempi pratici.

Assegnare una funzione anonima a una variabile

Il caso più comune per utilizzare una funzione anonima è assegnarla a una variabile. La riga 6 dell'esempio seguente mostra come sia possibile eseguire la variabile $sum come se fosse una funzione.

<?php
$sum = function($val1, $val2) {
    return $val1 + $val2;
};

echo $sum(3, 4); // Output: 7

Nota: a differenza delle funzioni normali, qui non possiamo chiamare la funzione prima della sua dichiarazione. Se nell'esempio spostiamo l'echo sopra la variabile $sum, lo script dà errore.

Funzioni anonime e callbacks

Un altro utilizzo tipico delle funzioni anonime è per la creazione di una funzione di callback. Una funzione di callback è una funzione che è possibile passare a un'altra funzione come argomento.

PHP ha molte funzioni native che accettano una funzione di callback, ma è anche possibile creare la propria funzione che accetta una callback.

Un esempio tipico si ha con la funzione PHP array_map() che, preso un array e una callback come argomenti, applica la funzione di callback a ciascun elemento dell'array.

Vediamo un esempio pratico

<?php
$array = [2, 4, 6];

array_map(function($val) {
	echo ($val * 2)."\n";
}, $array);

/* Output
4
8
12
*/

La funzione di callback calcola il doppio di ciascun elemento dell'array $array passato come argomento. Il codice precedente può anche essere riscritto assegnando la funzione anonima ad una variabile, per essere utilizzata come argomento di array_map()

<?php
$array = [2, 4, 6];

$double = function($val) {
	echo ($val * 2)."\n";
};

array_map($double, $array);

/* Output
4
8
12
*/

Funzioni anonime e closure

È possibile utilizzare le funzioni anonime per la creazione di closure (letteralmente chiusura). Con una closure è possibile utilizzare variabili esterne all'interno di una funzione anonima, anche se tali variabili non sono accessibili all'interno della stessa, in quanto hanno ambito locale.

Vediamo meglio con un esempio pratico

<?php
function helloFunction() {

    $hello = "buongiorno";

    return function($name) use ($hello) {
        $hello = ucfirst($hello); 
        return "$hello $name!";
    };
};

$helloFunction = helloFunction();
echo $helloFunction("Programmatori PHP"); // Buongiorno Programmatori PHP!

Analizziamo il codice passo passo:

  1. La funzione helloFunction() inizializza la variabile locale $hello e restituisce una funzione anonima.
  2. Nelle righe 6-9, la funzione anonima modifica la variabile $hello convertendo la prima lettera in maiuscolo e ritorna una stringa contenente i valori di $hello e $name.
    Possiamo notare la keyword use che ci consente di utillizzare la variabile esterna $hello all'interno della funzione anonima. Infatti normalmente, la funzione anonima non avrebbe accesso a questa variabile, poiché essa ha un ambito locale solamente per la funzione helloFunction().
  3. Alla riga 12 chiamiamo la funzione helloFunction() e assegnamo il valore restituito (ossia quello della funzione anonima) alla variabile $helloFunction.
  4. A questo punto, helloFunction() ha terminato la sua esecuzione. Normalmente, la variabile locale $hello sarebbe fuori dall'ambito della funzione anonima che viene chiamata alla riga successiva. Tuttavia, poiché abbiamo creato una closure, la funzione anonima può comunque accedere a questa variabile.
  5. Alla riga 13, chiamiamo la nostra funzione anonima che ritorna la stringa di testo "Buongiorno Programmatori PHP!".

La cosa importante da notare nell'esempio, è che la funzione anonima restituita può accedere alla variabile locale della funzione normale che racchiude, anche dopo che questa ha terminato la sua esecuzione.

Ciò evita l'uso di una cattiva pratica di programmazione, ossia l'utilizzo della keyword global, che consente di dichiarare come globale una variabile locale ampliando il suo scope.

In conclusione le funzioni anonime risultano utili nel caso in cui si abbia la necessità di utilizzare delle funzioni usa e getta per svolgere operazioni specifiche, senza doverle quindi definire come funzioni normali.