Estaba tan entusiasmado con mi artículo anterior sobre las macros de PHP, que pensé que sería divertido para nosotros explorar la intersección de las macros y la programación funcional.
PHP ya está lleno de funciones, con patrones orientados a objetos que emergen relativamente tarde en su vida. Aún así, las funciones de PHP pueden ser engorrosas, especialmente cuando se combinan con las reglas de alcance de las variable
En este ejemplo, vemos los lenguajes definidos como una lista de lenguajes de programación. Cada lenguaje de programación se combina con un prefijo constante y la matriz resultante se registra en la consola.
Esto es todo lo que vamos a ver de JavaScript. Si quieres aprender más sobre ES6, consulta la documentación de BabelJS.
No es significativamente más código, pero no es tan claro o idiomático como la alternativa de JavaScript. A menudo echo de menos la sintaxis expresiva y funcional de JavaScript cuando construyo cosas en PHP. Quiero intentar recuperar algo de esa sintaxis expresiva.
Comenzando
Como en el artículo anterior, vamos a usar la librería Yay de Márcio Almada. Podemos instalarla con
composer require yay/yay:*
Pondremos nuestro código Yay (muy similar al de PHP, pero con soporte para macros) en archivos que terminen en .yphp y los compilaremos a PHP normal con
vendor/bin/yay before.yphp > after.php
Una solución sencilla
Lo primero que quiero probar es mapear sobre una colección de cosas, con una sintaxis más parecida a JavaScript. Quiero algo como
$list->map(function($item) {
return strtoupper($item);
});
Ya podemos hacer eso, pero requiere crear una clase especial de PHP. No podemos usar funciones normales de arreglos en esta clase especial, así que la clase también necesita tener métodos para convertir a y desde arreglos nativos de PHP.
Si aún no lo has hecho, ahora es un buen momento para leer el artículo anterior, que explica cómo funciona este código. Definitivamente no deberías probar los siguientes ejemplos si no te sientes cómodo con lo que has visto hasta ahora…
Una solución compleja
Hemos empezado bien. Todavía hay una diferencia significativa entre JavaScript y PHP: el alcance de las variables. Si quisiéramos usar ese prefijo, tendríamos que vincularlo a la llamada de retorno dada a array_map(…). Vamos a trabajar alrededor de eso.
Utilizamos la función get_defined_vars() para almacenar todas las variables definidas actualmente en un array. El ámbito de éstas es el mismo en el que se ejecuta eval. A continuación, pasamos el contexto como un parámetro vinculado al cierre. También proporcionamos tanto claves como valores para la lista de origen.
Este es un extraño efecto secundario de cómo funciona array_map. Dependemos un poco de que el orden sea el mismo para los valores de retorno de array_keys y array_values, pero es una apuesta bastante segura.
Utilizamos la función extract para crear variables locales para cada una de las claves y valores del array $context. Esto significa que cada variable en el ámbito fuera de array_map estará disponible dentro también. Devolvemos el valor de —expresión, justo después de restablecer la variable de valor definida por el usuario.
Una vez más, podemos ver que el código generado no es el más bonito. Pero supera una limitación de alcance de variables bastante molesta, y permite una sintaxis abreviada para el enfoque tradicional de array_map.