Funciones anónimas
Las funciones anónimas, también llamadas cierres o closures
permiten la creación de funciones sin especificar su nombre.
Son particularmente útiles como funciones de retrollamada callable,
pero su uso no se limita a este solo uso.
Las funciones anónimas se implementan 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 cierre
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($nombre) {
printf("Hola %s\r\n", $nombre);
};
$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
$mensaje = 'hola';
// Sin "use"
$ejemplo = function () {
var_dump($mensaje);
};
$ejemplo();
// Hereda $mensaje
$ejemplo = function () use ($mensaje) {
var_dump($mensaje);
};
$ejemplo();
// El valor de la variable heredada se define cuando la función es
// definida no cuando es llamada
$mensaje = 'mundo';
$ejemplo();
// Reasignación de la variable mensaje
$mensaje = 'hola';
// Herencia por referencia
$ejemplo = function () use (&$mensaje) {
var_dump($mensaje);
};
$ejemplo();
// El cambio de valor en el contexto padre es reflejado al
// llamar a la función.
$mensaje = 'mundo';
$ejemplo();
// Las funciones anónimas también aceptan argumentos clásicos
$ejemplo = function ($arg) use ($mensaje) {
var_dump($arg . ' ' . $mensaje);
};
$ejemplo("hola");
// La declaración de tipo de retorno viene después de la cláusula use
$ejemplo = function () use ($mensaje): string {
return "hola $mensaje";
};
var_dump($ejemplo());
?>
El resultado del ejemplo
sería algo similar a:
Notice: Undefined variable: mensaje 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 ejecute. 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). Vea el
ejemplo a continuación:
Ejemplo #4 Funciones anónimas y contexto
<?php
// Un carrito de compra simple, que contiene una lista de productos
// elegidos 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 retrollamada anónima.
class Carrito
{
const PRECIO_MANTEQUILLA = 1.00;
const PRECIO_LECHE = 3.00;
const PRECIO_HUEVO = 6.95;
protected $productos = array();
public function add($producto, $cantidad)
{
$this->productos[$producto] = $cantidad;
}
public function getCantidad($producto)
{
return isset($this->productos[$producto]) ? $this->productos[$producto] :
FALSE;
}
public function getTotal($impuesto)
{
$total = 0.00;
$callback =
function ($cantidad, $producto) use ($impuesto, &$total)
{
$precioPorArticulo = constant(__CLASS__ . "::PRECIO_" .
strtoupper($producto));
$total += ($precioPorArticulo * $cantidad) * ($impuesto + 1.0);
};
array_walk($this->productos, $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 Enlace automático de $this
<?php
class Test
{
public function testing()
{
return function() {
var_dump($this);
};
}
}
$objeto = new Test;
$funcion = $objeto->testing();
$funcion();
?>
El resultado del ejemplo sería:
Cuando se declara en el contexto de una clase, la clase
actual es automáticamente enlazada, haciéndola $this
disponible en el contexto de la función. Si este enlace 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 enlazar automáticamente la clase actual a la función.
Los objetos también pueden no ser enlazados 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 enlace 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