Funciones anónimas

Las funciones anónimas, también llamadas closures o closures permiten la creación de funciones sin especificar su nombre. Son particularmente útiles como funciones de devolución de llamada callable, pero su utilización no se limita a este único uso.

Las funciones anónimas están implementadas utilizando la clase Closure.

Ejemplo #1 Ejemplos con funciones anónimas

<?php
echo preg_replace_callback('~-([a-z])~', function ($match) {
return
strtoupper($match[1]);
},
'hola-mundo');
?>

Las funciones anónimas también pueden ser utilizadas como valores de variables. PHP convertirá automáticamente estas expresiones en objetos Closure. Asignar un closure a una variable es lo mismo que una asignación clásica, incluyendo el punto y coma final.

Ejemplo #2 Asignación de función anónima a una variable

<?php
$saludo
= function($name) {
printf("Hola %s\r\n", $name);
};

$saludo('Mundo');
$saludo('PHP');
?>

Las funciones anónimas pueden heredar variables del contexto de su padre. Estas variables deben entonces ser pasadas en la construcción de lenguaje use. A partir de PHP 7.1, estas variables no deben incluir superglobals, $this, o variables con el mismo nombre que un parámetro. Una declaración de tipo de retorno para la función debe ser colocada después de la cláusula use.

Ejemplo #3 Herencia de variable desde el contexto padre

<?php
$message
= 'hola';

// Sin "use"
$example = function () {
var_dump($message);
};
$example();

// Hereda $message
$example = function () use ($message) {
var_dump($message);
};
$example();

// El valor de la variable heredada es definido cuando la función es
// definida no cuando es llamada
$message = 'mundo';
$example();

// Reinicialización de la variable message
$message = 'hola';

// Herencia por referencia
$example = function () use (&$message) {
var_dump($message);
};
$example();

// El cambio de valor en el contexto padre es reflejado al
// llamar a la función.
$message = 'mundo';
$example();

// Las funciones anónimas también aceptan argumentos clásicos
$example = function ($arg) use ($message) {
var_dump($arg . ' ' . $message);
};
$example("hola");

// Declaración de tipo de retorno viene después de la cláusula use
$example = function () use ($message): string {
return
"hola $message";
};
var_dump($example());
?>

El resultado del ejemplo sería algo similar a:

Notice: Undefined variable: message in /example.php on line 6
NULL
string(5) "hola"
string(5) "hola"
string(5) "hola"
string(5) "mundo"
string(11) "hola mundo"
string(11) "hola mundo"

A partir de PHP 8.0.0, la lista de variables heredadas del contexto puede incluir una coma final, que será ignorada.

La herencia del contexto padre no es lo mismo que las variables del entorno global. Las variables globales existen en el contexto global, que es el mismo, independientemente de la función que se esté ejecutando. El contexto padre de una función anónima es la función en la que la función fue declarada (no necesariamente la que llama). Véase el ejemplo siguiente:

Ejemplo #4 Funciones anónimas y contexto

<?php
// Un carrito de compra simple, que contiene una lista de productos
// seleccionados y la cantidad deseada de cada producto. Incluye
// un método que calcula el precio total de los elementos en el carrito
// utilizando una función de devolución de llamada anónima.
class Carrito
{
const
PRECIO_MANTEQUILLA = 1.00;
const
PRECIO_LECHE = 3.00;
const
PRECIO_HUEVO = 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__ . "::PRECIO_" .
strtoupper($product));
$total += ($pricePerItem * $quantity) * ($tax + 1.0);
};

array_walk($this->products, $callback);
return
round($total, 2);
}
}

$mi_carrito = new Carrito;

// Añadir elementos al carrito
$mi_carrito->add('mantequilla', 1);
$mi_carrito->add('leche', 3);
$mi_carrito->add('huevo', 6);

// Mostrar el precio con 5.5% de IVA
print $mi_carrito->getTotal(0.055) . "\n";
// El resultado será 54.29
?>

Ejemplo #5 Vinculación automática de $this

<?php

class Test
{
public function
testing()
{
return function() {
var_dump($this);
};
}
}

$object = new Test;
$function = $object->testing();
$function();

?>

El resultado del ejemplo sería:

object(Test)#1 (0) {
}

Cuando se declara en el contexto de una clase, la clase actual es automáticamente vinculada, haciéndola $this disponible en el contexto de la función. Si este vínculo automático de la clase actual no es deseado, entonces las funciones anónimas estáticas pueden ser utilizadas en su lugar.

Las funciones anónimas estáticas

Las funciones anónimas pueden ser declaradas estáticamente. Esto permite no vincular automáticamente la clase actual a la función. Los objetos también pueden no ser vinculados durante la ejecución.

Ejemplo #6 Intento de uso de $this en una función anónima estática

<?php

class Foo
{
function
__construct()
{
$func = static function() {
var_dump($this);
};
$func();
}
};
new
Foo();

?>

El resultado del ejemplo sería:

Notice: Undefined variable: this in %s on line %d
NULL

Ejemplo #7 Intento de vinculación de un objeto a una función anónima estática

<?php

$func
= static function() {
// cuerpo de la función
};
$func = $func->bindTo(new stdClass);
$func();

?>

El resultado del ejemplo sería:

Warning: Cannot bind an instance to a static closure in %s on line %d

Historial de cambios

Versión Descripción
8.3.0 Los closures creados a partir de las métodos mágicos pueden aceptar argumentos nombrados.
7.1.0 Las funciones anónimas no pueden cerrarse sobre superglobals, $this, o cualquier variable con el mismo nombre que un parámetro.

Notas

Nota: Es posible utilizar las funciones func_num_args(), func_get_arg() y func_get_args() en una función anónima.