back to top

Anonymous functions e Closures in PHP 5.3

A partire da PHP 5.3 sono disponibili le Anonymous functions (Lambda functions) e le Closures… ma di cosa si tratta?

Anonymous functions

Le funzioni anonime ( o lambda ) sono funzioni ( senza nome ) che hanno come utilizzo principale ( anche se non unico ) quello di essere definite come funzioni di callback.

Per chi di voi si chiedesse cos’è una funzione di callback potrei semplificare la definizione in questo modo: una funzione passata come argomento di un altra funzione.

Forse è meglio vedere un esempio, per chiarezza vediamolo prima scritto in pseudocodice, le anonymous e i callback non sono infatti prerogativa di PHP:

// # Callback
function callback( parametro ) 
DO qualcosa con il parametro
return risultato elaborazione

// # Chiamante
function chiamante ( input, callback( parametro) )

Non è ancora chiaro vero? Nessun problema, vediamo un esempio pratico utilizzando la funzione di libreria array_walk la cui signature è:

bool array_walk ( array &$array , callback $funcname [, mixed $userdata ] )

Questa funzione applica ad ogni elemento dell’array $array la funzione di callback $funcname ( tralasciamo $userdata che è opzionale ).

Prima della versione 5.3 di PHP per utilizzarla avremmo dovuto scrivere ad esempio:

$array = array( "Rick", "Giorgio", "Matteo" );
function echoEach ( $item ) {
  echo $item . "<br />";
}

array_walk( $array, "echoEach" );

Vediamo come cambia con l’uso delle Lambda:

$array = array( "Rick", "Giorgio", "Matteo" );
array_walk( $array, function( $item ) {
  echo $item . "<br />";
});

Per entrambe le versioni l’output sarà:

Rick
Giorgio
Matteo

Altro esempio, la funzione array_filter, che accetta un array in input ed un callback, signature:

array array_filter ( array $input [, callback $callback ] )

Utilizziamo le funzioni anonime:

$arrayNum = array( 1, 3, 6, 5, 2, 8 );
$filtered = array_filter( $arrayNum, function( $item ){
  return $item > 2;
});

print_r( $filtered );

L’output:

Array
(
  [1] => 3
  [2] => 6
  [3] => 5
  [5] => 8
)

Ossia un array filtrato per i valori maggiori di 2.

Cosa guadagnamo? In leggibilità ed eleganza del codice.

Le Closures

La Closures sono in buona sostanza delle funzioni anonime che fanno uso del contesto che le circonda; meglio delle definizioni un esempio:

$closure = function( $param1, $param2 ) {
  return $param1 + $param2;
};

$added = $closure( 1, 4 );
echo $added;

Output:

5

La differenza tra le Lambda e Closure è molto piccola, vediamo un esempio che chiarisca meglio il delta:

$factor = 3;
$closureScoped = function ( $multiply ) use ( $factor ) {
  return $multiply * $factor;
};

$multiplied = $closureScoped( 4 );
echo $multiplied;

Output:

12

Notate l’utilizzo della keyword use, che permette alla funzione anonima salvata nella variabile $closureScoped di importare nel proprio scope la variabile $factor e di farne uso.

Una Closure può addirittura modificare una variabile “globale”, basta passarla per ref:

$x = 2;
$closureRef = function() use (&$x) {
  $x+=2;
};

echo $x . "<br />";
$closureRef();
echo $x . "<br />";
$closureRef();
echo $x . "<br />";

Output:

2
4
6

Il metodo __invoke()

Utilizzando il metodo “magico” __invoke in una classe possiamo rendere in buona sostanza l’intera classe una closure:

class ClosureExample {
  public function __invoke() {
  echo "INVOCATA DIRETTAMENTE";
  }
}

$closureExample = new ClosureExample();
$closureExample();

Output:

INVOCATA DIRETTAMENTE

Lo scope

Le closures possono ereditare le variabili non solo dallo scope globale ( come nel caso delle variabili $factor e $x degli esempi sopra riportati ) ma anche dal parent scope. Il parent scope è lo scope della funzione che racchiude la closure, vediamo un esempio pratico:

class ClosureParentScope {

  public $members = array();

  public function setMembers( $members) {
    $this->members = $members;
  }

  public function parentC( $pad ) {

  $space = " ";
  $closureCallback = function ( $item ) use ( $space, $pad ) {
    echo $item . $space . $pad . $space;
  };

  array_walk( $this->members, $closureCallback );
  }
}

$cps = new ClosureParentScope;
$cps->setMembers( array( "Marco", "Luca", "Giada", "Danilo" ) );
$cps->parentC( "-" );

Output

Marco - Luca - Giada - Danilo - 

La closure ha utilizzato sia $space che $pad, presi dal parent scope ( scope di parentC )

Conclusioni

Per chi utilizza jQuery sarà molto facile comprendere ed utilizzare le funzioni anonime e le closures anche in PHP, ma per tutti vale il consiglio di utilizzarle quando il contesto le permette. Il risultato sarà un codice più ordinato e leggibile.

Altri contenuti interessanti

Pubblicità

Leggi anche...

Cannot modify header information – headers already sent: come risolvere l’errore PHP

L'errore di PHP cannot modify header information - headers...

Ricavare l’estensione di un file con PHP

Quando si lavora con i file in un'applicazione web,...

GD Library: creazione, manipolazione e ridimensionamento immagini con PHP

Le librerie GD (o GD Library), sono componenti fondamentali...

PHP: impostare il fuso orario italiano

Le tue pagine PHP non mostrano l’orario corretto? Probabilmente...

5 script PHP per gestire BBCode

A volte può aversi l'esigenza di dover offrire agli...
Pubblicità