Advertisement
  1. Code
  2. PHP

Programación funcional en PHP con funciones lambda

Scroll to top
Read Time: 11 min

Spanish (Español) translation by Ana Paulina Figueroa (you can also view the original English article)

Uno de los aspectos positivos de la programación, incluida la programación PHP, es que es posible resolver el mismo problema de varias maneras. Esto permite a las personas mostrar su creatividad y encontrar soluciones increíblemente eficientes y únicas. Puedes ver ejemplos de esto en acción cuando buscas programas que enumeran o encuentran números primos.

Del mismo modo, existen diferentes estilos de escritura de programas. Dos tipos de estilo comunes son la programación funcional y la programación orientada a objetos. El estilo de programación funcional se basa en dividir las tareas en funciones separadas. Estas funciones reciben algunos argumentos y luego devuelven un solo valor. El valor devuelto se basa únicamente en la entrada proporcionada.

Este tutorial te enseñará cómo usar la programación funcional con funciones PHP lambda.

Programación funcional en PHP

En la programación, las funciones se utilizan para agrupar una serie de instrucciones que actúan sobre una entrada opcional para producir un resultado. Hay una clase especial de funciones, llamadas funciones de primera clase, que son tratadas por el lenguaje de programación como ciudadanos de primera clase. En términos simples, esto significa que, en esos lenguajes de programación, las funciones se pueden enviar como argumentos a otras funciones, usarse como valores devueltos o asignarse a otras variables.

El soporte para funciones de primera clase se introdujo en la programación PHP con la versión 5.3. Esto nos permite crear funciones anónimas (también llamadas funciones lambda) y cierres en PHP. En este tutorial, aprenderás todos los conceptos importantes que necesitas saber sobre las funciones lambda PHP.

Funciones anónimas o lambda PHP

Los términos "funciones anónimas" y "funciones lambda" a menudo se usan indistintamente, lo que puede ser confuso para las personas, porque el manual de programación PHP no usa el término "funciones lambda" en ninguna parte de su artículo sobre funciones anónimas. Sin embargo, si indagas un poco más encontrarás una página RFC sobre cierres que trata sobre las funciones lambda.

Puedes comprender mejor la utilidad de las funciones lambda PHP con la ayuda de algunos ejemplos. Como ya sabes, en la programación PHP hay algunas funciones integradas que aceptan otras funciones como argumentos. Estas funciones de devolución de llamada actúan sobre los datos proporcionados y generan un resultado final. Por ejemplo, la función array_map() acepta una función de devolución de llamada como su primer parámetro.

Sin funciones PHP lambda, estarás limitado a una de las tres opciones siguientes:

  1. Definir la función en otro lugar y luego hacer referencia a ella usando su nombre dentro de array_map(). Esto te obligará a moverte hacia adelante y hacia atrás en tu archivo para ver la definición de la función cada vez que la necesites.
  2. Definir las funciones de devolución de llamada dentro de array_map() y especificar un nombre. Sin embargo, aún necesitarás verificar que no haya un conflicto de nombres usando function_exists().
  3. Simplemente crear la función en tiempo de ejecución usando create_function() en PHP. Esto puede parecer una buena idea al principio, pero no lo es. Puede dificultar la lectura del código, ocasionar una caída del rendimiento y problemas de seguridad. De hecho, PHP 8.0.0 ha eliminado create_function() del lenguaje.

Las funciones PHP lambda, o funciones anónimas, eliminan todos estos inconvenientes al permitirte definir funciones en el lugar en el que se utilizan, sin necesidad de asignarles un nombre. También se compilan antes del tiempo de ejecución, por lo que no ocasionan la caída del rendimiento.

Este es un ejemplo de una función anónima en PHP:

1
<?php
2
3
$numbers = range(15, 20);
4
5
print_r(array_map(function($n){
6
    return $n**2;
7
}, $numbers));
8
9
/*

10
Array

11
(

12
    [0] => 225

13
    [1] => 256

14
    [2] => 289

15
    [3] => 324

16
    [4] => 361

17
    [5] => 400

18
)

19
*/
20
21
?>

En el ejemplo anterior, estamos creando una nueva matriz con los cuadrados de números originales usando array_map(). Como puedes ver, no hubo necesidad de especificar un nombre único para la función de devolución de llamada, y su definición se proporcionó en donde fue usada, por lo que no tuvimos que brincar por el código para ver qué hace.

Comprende los cierres en la programación PHP

Básicamente, los cierres son funciones lambda PHP que pueden acceder a variables de su ámbito padre. Ya hemos visto los fundamentos del ámbito de las variables en PHP en un tutorial anterior. Esto aumenta la utilidad de los cierres, al permitirnos escribir funciones más flexibles y de propósito general.

Intentemos reescribir la función de la sección anterior para que pueda calcular el valor de la potencia con cualquier número, en lugar de solo 2. Al principio, quizá intentes escribir el código de la siguiente manera:

1
<?php
2
3
$numbers = range(15, 20);
4
5
$pow = 2;
6
7
print_r(array_map(function($n){
8
    return $n**$pow;
9
}, $numbers));
10
11
// Advertencia PHP: Variable $pow no definida

12
13
/*

14
Array

15
(

16
    [0] => 1

17
    [1] => 1

18
    [2] => 1

19
    [3] => 1

20
    [4] => 1

21
    [5] => 1

22
)

23
*/
24
25
?>

Esto te mostrará una advertencia sobre una variable $pow no definida y generará una matriz con los valores incorrectos. Puedes resolver este problema utilizando la palabra clave global para acceder a la variable dentro de la función de devolución de llamada. Sin embargo, ese enfoque tiene sus propios inconvenientes, de los que ya he hablado en el tutorial sobre el ámbito de las variables.

En la programación PHP, cuentas con una palabra clave especial llamada use, que te proporciona acceso a las variables del ámbito padre. Estas funciones PHP lambda, que aprovechan la palabra clave use para acceder a variables que están fuera de su ámbito, se denominan cierres. El siguiente ejemplo de código ilustra su uso:

1
<?php
2
3
$numbers = range(15, 20);
4
5
$pow = 2;
6
7
print_r(array_map(function($n) use($pow) {
8
    return $n**$pow;
9
}, $numbers));
10
11
/*

12
Array

13
(

14
    [0] => 225

15
    [1] => 256

16
    [2] => 289

17
    [3] => 324

18
    [4] => 361

19
    [5] => 400

20
)

21
*/
22
23
?>

Algo importante que debes recordar es que las variables se envían como valores dentro de la función. Esto significa que los cambios que realices en una variable del ámbito padre no serán visibles fuera del cierre. Este es un ejemplo:

1
<?php
2
3
$numbers = range(1, 5);
4
5
$calls = 0;
6
7
for($i = 6; $i <= 20; $i+=6) {
8
    print_r(array_map(function($n) use($i, $calls) {
9
        $calls += 1;
10
        return $n*$i;
11
    }, $numbers));
12
}
13
14
echo $calls;
15
16
/*

17
Array

18
(

19
    [0] => 6

20
    [1] => 12

21
    [2] => 18

22
    [3] => 24

23
    [4] => 30

24
)

25
Array

26
(

27
    [0] => 12

28
    [1] => 24

29
    [2] => 36

30
    [3] => 48

31
    [4] => 60

32
)

33
Array

34
(

35
    [0] => 18

36
    [1] => 36

37
    [2] => 54

38
    [3] => 72

39
    [4] => 90

40
)

41
*/
42
43
44
echo $calls;
45
// Resultado: 0

46
47
?>

En el ejemplo anterior, pasamos por el bucle for tres veces y luego incrementamos el valor de $calls en 1 durante cada una de las cinco llamadas a nuestra función anónima. Por tanto, el valor final de $calls debió haber sido 15. Sin embargo, simplemente se queda en 0.

Una forma de mantener el valor de $calls a través de las iteraciones, así como fuera del cierre, es enviarlo como referencia.

1
<?php
2
3
$numbers = range(1, 5);
4
5
$calls = 0;
6
7
for($i = 6; $i <= 20; $i+=6) {
8
    print_r(array_map(function($n) use($i, &$calls) {
9
        $calls += 1;
10
        return $n*$i;
11
    }, $numbers));
12
}
13
14
/*

15
Array

16
(

17
    [0] => 6

18
    [1] => 12

19
    [2] => 18

20
    [3] => 24

21
    [4] => 30

22
)

23
Array

24
(

25
    [0] => 12

26
    [1] => 24

27
    [2] => 36

28
    [3] => 48

29
    [4] => 60

30
)

31
Array

32
(

33
    [0] => 18

34
    [1] => 36

35
    [2] => 54

36
    [3] => 72

37
    [4] => 90

38
)

39
*/
40
41
echo $calls;
42
// Resultado: 15

43
44
?>

Funciones de flecha en PHP

Las funciones de flecha se introdujeron en PHP 7.4, y simplemente proporcionan una manera más concisa de escribir funciones anónimas o lambda. Estas llevan el concepto de los cierres al siguiente nivel y envían automáticamente todas las variables del ámbito padre al ámbito de nuestra función lambda PHP. Esto significa que ya no necesitas importar variables con la palabra clave use.

1
<?php
2
3
$numbers = range(1, 5);
4
5
for($i = 6; $i <= 20; $i+=6) {
6
    print_r(array_map(fn($n) => $n*$i, $numbers));
7
}
8
9
/*

10
Array

11
(

12
    [0] => 6

13
    [1] => 12

14
    [2] => 18

15
    [3] => 24

16
    [4] => 30

17
)

18
Array

19
(

20
    [0] => 12

21
    [1] => 24

22
    [2] => 36

23
    [3] => 48

24
    [4] => 60

25
)

26
Array

27
(

28
    [0] => 18

29
    [1] => 36

30
    [2] => 54

31
    [3] => 72

32
    [4] => 90

33
)

34
*/
35
36
?>

Ten en cuenta que, por defecto, las variables se envían por valor en lugar de por referencia, pero aún es posible enviarlas por referencia si así lo deseas.

Funciones de orden superior

Las funciones que reciben una función como argumento o devuelven una función como su valor se denominan funciones de orden superior. Como aprendimos al principio de este tutorial, PHP tiene un soporte adecuado para las funciones de primera clase. Esto significa que también podemos escribir nuestras funciones de orden superior en PHP.

Usemos todo lo que hemos aprendido hasta ahora para crear una función de orden superior que genere oraciones simples a partir de los valores enviados.

1
<?php
2
3
function make_sentences($topic) {
4
    if($topic == "comida") {
5
        return fn($a, $b) => "$a come $b.";
6
    }
7
    if($topic == "lugar") {
8
        return fn($a, $b) => "$a vive en $b.";
9
    }
10
}
11
12
?>

La función anterior acepta un único parámetro que especifica el tema de referencia para generar nuestras oraciones. Dentro de la función, usamos algunas instrucciones condicionales para devolver una función de flecha, que a su vez devuelve una cadena concatenada.

Ahora crearemos tres matrices diferentes que contienen los nombres de personas, frutas y planetas. Estas matrices se enviarán de dos en dos a la función array_map(), junto con nuestra función make_sentences(), que es una devolución de llamada.

1
<?php
2
3
function make_sentences($topic) {
4
    if($topic == "comida") {
5
        return fn($a, $b) => "$a come $b.";
6
    }
7
    if($topic == "lugar") {
8
        return fn($a, $b) => "$a vive en $b.";
9
    }
10
}
11
12
$people = ["Adam", "Andrew", "Monty"];
13
$fruits = ["manzanas", "plátanos", "mangos"];
14
$planets = ["Marte", "la Tierra", "Venus"];
15
16
print_r(array_map(make_sentences("comida"), $people, $fruits));
17
/*

18
Array

19
(

20
    [0] => Adam come manzanas.

21
    [1] => Andrew come plátanos.

22
    [2] => Monty come mangos.

23
)

24
*/
25
26
print_r(array_map(make_sentences("lugar"), $people, $planets));
27
/*

28
Array

29
(

30
    [0] => Adam vive en Marte.

31
    [1] => Andrew vive en la Tierra.

32
    [2] => Monty vive en Venus.

33
)

34
*/
35
36
?>

Como puedes ver, hemos podido generar algunas oraciones simples tomando los elementos correspondientes de dos matrices diferentes y uniéndolos en una cadena. Deberías intentar introducir una variable adicional dentro de la función make_sentences(), que luego podrás utilizar en las funciones de flecha para crear oraciones un poco más complicadas.

Reflexiones finales

En este tutorial, hemos cubierto muchos temas relacionados entre sí de una manera u otra. Comenzamos con una breve introducción a la programación funcional en PHP. Luego continuamos con algunas características útiles del lenguaje, como las funciones PHP lambda o anónimas, los cierres y las funciones de flecha. Ahora deberías tener buenas nociones de todos estos términos y de cómo son diferentes, aún cuando están relacionados entre sí. Finalmente, aprendimos a crear nuestras propias funciones de orden superior en PHP.

Con suerte, todos estos conceptos te ayudarán a escribir código más seguro y más claro en tus proyectos futuros.

Advertisement
Did you find this post useful?
Want a weekly email summary?
Subscribe below and we’ll send you a weekly email summary of all new Code tutorials. Never miss out on learning about the next big thing.
Advertisement
Looking for something to help kick start your next project?
Envato Market has a range of items for sale to help get you started.