¿ PHP Funcional ? Bueno, PHP no es un lenguaje funcional, pero algunas técnicas funcionales se pueden utilizar para mejorar nuestro código: mejor legibilidad, más fácil de mantener => código más barato.
Durante muchos años, PHP se escribió proceduralmente, todo en un solo archivo con funciones en todas partes. Después de la versión 5. *, las aplicaciones se han escrito utilizando el paradigma orientado a objetos (Object Oriented paradigm , OO). Pero pocas veces pensamos en PHP y paradigma funcional. Por supuesto, PHP no es un lenguaje funcional, pero deberíamos poder usar lo mejor de cada paradigma. No se trata de OO contra la programación funcional (FP), o definir cuál es mejor.
Debido a que PHP es un entorno de OO bastante «clásico», sugerimos un enfoque de «fusión». Nuestro enfoque va en la dirección de lo que usamos en los lenguajes multiparadigma, como Scala, Kotlin, pero también en Typescript: el que llamamos «Object-Functional». De ahí PHP Funcional. Seguimos creando clases y objetos pero, en este caso, utilizando una mentalidad funcional. En lugar de decirle al ordenador cómo resolver los problemas (también conocida como programación imperativa), comenzamos por decirle al ordenador lo que queremos lograr (programación declarativa).
Programación funcional y PHP funcional
En pocas palabras, la programación funcional:
Evita la mutación del estado Una vez que se crea un objeto, nunca cambia. No hay variables como las usamos en PHP.
Utiliza un sistema de tipos complejo Un tipo es un clasificador para un valor. Proporciona información sobre cuál será ese valor en tiempo de ejecución, pero se indica en tiempo de compilación. Producen, por ejemplo, funciones con más detalle (se puede ver lo que espera la función, cuál será el resultado), y como recompensa por eso, pueden detectar errores en tiempo de compilación, tan pronto como en su IDE mientras codifica . PHP tiene su propio «tiempo de compilación», generalmente etiquetado como «tiempo de análisis sintáctico», pero en realidad es similar, si no es un sinónimo, especialmente cuando se utilizan herramientas como OpCache para almacenar en caché el resultado del análisis sintáctico. Vale la pena mencionar que los tipos en las versiones actuales de PHP son algo «más débiles» que otros lenguajes funcionales, o incluso cuando se compara con otros lenguajes OO «clásicos».
Funciones como valores de primera clase Las funciones se pueden usar como entradas o salidas de otras funciones que permiten la composición de funciones. No son las funciones que conocemos en PHP. Son funciones matemáticas: la misma entrada produce siempre la misma salida (no importa cuántas veces se la llame). Se llaman funciones puras.
Funciones puras o impuras
Funciones puras
no hay globales; los valores no se pasan por referencia
no tiene efectos secundarios (una propiedad muy interesante !!)
no use ningún tipo de bucles (for, foreach, while …)
Funciones impuras
Mutan el estado global
Pueden modificar sus parámetros de entrada
Pueden arrojar excepciones
Pueden realizar cualquier operación de E / S: necesitan hablar con recursos externos como bases de datos, red, sistema de archivos …
Pueden producir resultados diferentes incluso con los mismos parámetros de entrada.
Pueden tener efectos secundarios
Be functional my friend – PHP Funcional
Veamos algunos ejemplos prácticos para ver como podemos ser más funcionales: Evitar variables temporales Sin variables temporales en nuestro código, evitamos tener un estado local que puede producir resultados no deseados. En el siguiente ejemplo, mantenemos el estado hasta que se devuelve al final.
El último refactor: eliminar el if. Finalmente, tenemos una versión más funcional:
function isPositive(int $number) {
return $number > 0;
}
Funciones pequeñas
Deben seguir el principio de responsabilidad única (SRP): hacer solo una cosa
Eso significa que son más fáciles de testear
Podemos componer otras funciones
function sum(int $number1, int $number2) {
return $number1 + $number2;
}
echo sum(sum(3, 4), sum(5, 5));
// 17
Fijémonos en que podríamos cambiar la suma (3, 4) por 7 y el resultado sería el mismo:
echo sum(7, sum(5, 5));
// 17
Esto se llama transparencia referencial: una función puede ser reemplazada por su resultado y el resultado final no cambia en absoluto.
Eliminar el estado
Esto puede ser bastante difícil cuando estamos acostumbrados a escribir de manera imperativa. En este ejemplo, calcula el producto de todos los valores en un array. Para hacerlo, usamos algunos agregadores y un bucle para iterar sobre él.
Nuestras aplicaciones PHP a menudo necesitan alguna entrada de recursos externos y producen algunos resultados. Eso significa que puede ser difícil tener funciones puras. En estos casos, debemos dividir nuestro código impuro de el puro. Por ejemplo, usando el código de php.net sobre la lectura de un archivo:
the HTML source of a URL.
$lines = file('https://www.google.com/');
// Loop through our array, show HTML source as HTML source
foreach ($lines as $line_num => $line) {
echo htmlspecialchars($line) . "
\n";
}
Lee el contenido de un sitio externo (entrada externa) y muestra los resultados en la consola (salida externa). ¿Podemos hacer algunos cambios funcionales aquí? Claro, recorta el código en diferentes funciones.
function getFileContent($file) {
return file($file);
}
function formatLines($lines) {
return array_map(function($line) {
return htmlspecialchars($line) . "\n";
}, $lines);
}
print_r(formatLines(getFileContent('https://www.google.com/')));
El resultado final es el mism pero ahora tenemos:
Una función impura (getFileContent) que es fácilmente mockeable en nuestros tests
Una función pura (formatLines) que siempre devuelve el mismo resultado y que es fácilmente testeable.
No uses bucles para iterar sobre arrays Los bucles son imperativos, usan algunas variables temporales y no son muy legibles.
Mapa Necesitamos iterar sobre una matriz para modificar cada uno de sus contenidos. Ejemplo: recibimos una lista de usuarios de la base de datos y necesitamos devolver el modelo de dominio que nuestra aplicación espera. De una manera imperativa, haríamos esto: uso de un foreach diciéndole al ordernador qué hacer:
function findUsersMap()
{
return array_map("convertUser", getUsers());
}
function convertUser(array $user) {
return new UserDTO($user);
}
Usamos array_map en lugar de foreach y creamos una función pura que su único propósito es convertir el formato del usuario. Esta versión es mucho más legible que la anterior.
Filtrar Iterando sobre un array pero devolviendo solo los resultados que pasan algunas condiciones. Ahora que tenemos la lista de usuarios, queremos mostrar solo a los que viven en Barcelona. Una vez más, necesitamos revisar el array y verificar una por una su ciudad.
function getUsersFromBcn(array $users) {
$bcnUsers = [];
foreach ($users as $user) {
if ($user->getCity() == "Barcelona") {
$bcnUsers[] = $user;
}
}
return $bcnUsers;
}
O podríamos preguntar solo por los usuarios de Barcelona:
function getUsersFromBcn(array $users) {
return array_filter($users, "isFromBcn");
}
function isFromBcn(UserDTO $user) {
return $user->getCity() == "Barcelona";
}
Este código es mucho más simple y fácil de probar sin variables temporales ni foreach + if loops.
Reducir / fold Reducir un array para devolver un valor.
Ahora, queremos calcular el promedio de mascotas en la ciudad de Barcelona. Vamos a recorrer los usuarios de Barcelona calculando el número de mascotas:
Si tenemos múltiples condiciones, podríamos terminar con una oración muy larga que puede ser muy difícil de leer. Desafortunadamente, para resolver este problema, no lo podemos hacer en PHP nativo. Afortunadamente, hay algunas buenas bibliotecas para usar tuberías.
Laravel Collectton
El framework Laravel tiene una gran biblioteca para trabajar con arrays, a los que llaman colecciones. Se puede usar fuera de laravel si lo instalamos a través de composer
composer require tightenco/collect
Usando esta biblioteca, los objetos son inmutables y el código es legible, más declarativo. Nuestro ejemplo del promedio de mascotas en Barcelona sería:
Obtener el promedio (método de la biblioteca que hace la reducción + cálculo del promedio)
Conclusión: PHP funcional
Sabemos que PHP no es 100% funcional. Y cambiar la forma en que programamos de manera funcional no es una tarea fácil. Pero podemos comenzar a aplicar algunos de estos enfoques sencillos que simplifican nuestro código, lo hacen mucho más legible, más testeable y con menos efectos secundarios. Podemos empezar a pensar de una manera más declarativa y paso a paso seremos más funcionales. Continuaremos hablando sobre PHP funcional en próximos artículos, haciendo que nuestro PHP sea cada vez más funcional.
Si estás interesado en recibir más artículos sobre PHP funcional, no te olvides de suscribirse a nuestro boletín mensual aquí.
Si este artículo sobre PHP funcional te gustó, te puede interesar:
Experienced Full Stack Engineer with a demonstrated history of working in the information technology and services industry. Skilled in PHP, Spring Boot, Java, Kotlin, Domain-Driven Design (DDD), TDD and Front-end Development. Strong engineering professional with a Engineer's degree focused in Computer Engineering from Universitat Oberta de Catalunya (UOC).
Apiumhub reúne a una comunidad de desarrolladores y arquitectos de software para ayudarte a transformar tu idea en un producto potente y escalable. Nuestro Tech Hub se especializa en Arquitectura de Software, Desarrollo Web & Desarrollo de Aplicaciones Móviles. Aquí compartimos con usted consejos de la industria & mejores prácticas, basadas en nuestra experiencia.