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:

object(Test)#1 (0) {
}

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

Historial de cambios

Versión Descripción
8.3.0 Los cierres creados a partir de los métodos mágicos pueden aceptar parámetros nombrados.
7.1.0 Las funciones anónimas pueden no cerrarse sobre las 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.