El primero de los principios SOLID, “Principio de Responsabilidad Única”, se suele definir como que «una clase solo puede tener una sola responsabilidad». Pero este principio también puede aplicarse a fragmentos más pequeños de código, como veremos en este artículo:

Un loop solo debe tener una responsabilidad

Vamos a revisar el siguiente fragmento de código:

$recipes = [
    [
        'title' => 'Hamburguesa de pollo',
        'vegetarian' => false,
    ],
    [
        'title' => 'Pizza margarita',
        'vegetarian' => true,
    ],
    [
        'title' => 'Albóndigas de carne',
        'vegetarian' => false,
    ],
    [
        'title' => 'Ensalada capresa',
        'vegetarian' => true,
    ],
    //...
 ];

$vegetarianRecipeTitles = [];

foreach ($recipes as $recipe) {
   if ($recipe['vegetarian']) {
       $vegetarianRecipeTitles[] = $recipe['title'];
   }
}

dd($vegetarianRecipeTitles);
// array:2 [
//   0 => "Pizza margarita"
//   1 => "Ensalada capresa"
// ]

Este fragmento de código, tan sencillo como parece, puede simplificarse si utilizamos algunas funciones provistas por el lenguaje PHP o de la clase Collection que nos proporciona Laravel.

Pero es difícil ver esto porque nuestro loop parece bien específico y esto es porque tiene 2 responsabilidades combinadas:

  1. Filtramos por tipo de receta
  2. Agregamos los nombres de las recetas a un nuevo arreglo

Vamos a intentar dividir este loop en 2 separando sus responsabilidades, para ello lamentablemente necesitaremos una segunda variable:

$vegetarianRecipes = [];

foreach ($recipes as $recipe) {
   if ($recipe['vegetarian']) {
       $vegetarianRecipes[] = $recipe;
   }
}

$vegetarianRecipeTitles = [];

foreach ($vegetarianRecipes as $recipe) {
   $vegetarianRecipeTitles[] = $recipe['title'];
}

Cómo puedes ver, ahora tenemos 2 loops más pequeños y 2 variables locales en vez de una. En apariencia el código no es más sencillo, pero revisemos lo que hace:

El primer loop filtra y agrega los items resultantes a un nuevo arreglo (vegetarianRecipes), aquí podríamos haber aprovechado para agregar solamente los títulos, pero esta responsabilidad la dejamos a un segundo loop que recorre el nuevo arreglo y agrega los títulos al arreglo final (vegetarianRecipeTitles).

Nota que en este segundo loop no necesitamos filtrar, solo transformar los datos (de un arreglo asociativo a un arreglo sencillo con cadenas de texto).

Este paso de dividir loops, en apariencia innecesario, nos permite ahora usar funciones de PHP. Para la parte de filtrar usemos array_filter en vez de un ciclo con un if:

$vegetarianRecipes = array_filter($recipes, function ($recipe) {
    return $recipe['vegetarian'];
});

Por otro lado el segundo ciclo puede refactorizarse si utilizamos array_map en vez de un ciclo:

$vegetarianRecipeTitles = array_map(function ($recipe) {
    return $recipe['title']; 
}, $vegetarianRecipes);

Con esto obtenemos el mismo resultado utilizando 2 funciones provistas por el lenguaje en vez de ciclos y condicionales.

Introduciendo la clase Collection

En el curso de colecciones con Laravel encontrarás éste y otros ejemplos con videos más detallados; pero para darte un abreboca, veamos cómo podemos transformar el código anterior en una sola línea usando las colecciones de Laravel:

$vegetarianRecipeTitles = collect($recipes)
    ->filter(function($recipe) {
        return $recipe['vegetarian'];
    })
    ->map(function ($recipe) {
        return $recipe['title'];
    });

(Sí, el código está en varias líneas, pero tenemos un solo punto y coma fuera de las funciones).

Podemos reducir el código anterior con Arrow Functions a partir de PHP 7.4:

$vegetarianRecipeTitles = collect($recipes)
    ->filter(fn($recipe) => $recipe['vegetarian'])
    ->map(fn($recipe) => $recipe['title']);

El resultado con el uso de colecciones es ligeramente diferente, porque ahora tenemos una colección, no un arreglo:

=> Illuminate\Support\Collection {#1136
     all: [
       1 => "Pizza margarita",
       3 => "Ensalada capresa",
     ],
   }

Podemos obtener el arreglo usando el método all():

// 
$vegetarianRecipeTitles->all();

También podemos convertir colecciones a JSON con el método toJson y muchos más.

Te invito a aprende más sobre este tema en el nuevo Curso de colecciones en Laravel, donde veremos ejemplos más avanzados usando la versiones más recientes del framework Laravel.

Adicionalmente puedes aprender más sobre Refactorización con nuestro Curso de refactorización con PHP y más sobre aplicar principios SOLID en nuestro Curso de Patrones de Diseño con PHP.

Material relacionado

Únete a nuestra comunidad en Discord y comparte con los usuarios y autores de Styde, 100% gratis.

Únete hoy

Regístrate hoy en Styde y obtén acceso a todo nuestro contenido.