Desarrollo

Estructuras de control en PHP – 2ª parte

Desarrollo PHP

En la primera parte de la explicación de las estructuras de control en PHP vimos cómo utilizar IF, ELSE, WHILE y alguna otra cosita. En esta ocasión, y después de haber visto cómo trabajar con arrays en PHP y definido las estructuras de control FOR y FOREACH, vamos a ver cómo utilizar estas últimas en PHP.

Utilización de FOR

Ciertamente, en el artículo donde definimos el bucle FOR ya vimos muy por encima la forma típica en la que se utiliza. Dentro de la propia especificación del FOR encontraremos tres expresiones que van separadas por puntos y comas. La primera corresponde a la asignación de la variable que recorrerá el bucle. La segunda será la condición de parada y la tercera será el cambio del valor de la variable en cada iteración.

<?php

// Bucle FOR definido entre llaves
for ($i = 0; $i < 5; $i++) {
  echo $i;
}

// Bucle FOR definido entre dos puntos y sentencia final
for ($i = 0; $i < 5; $i++):
  echo $i;
endfor;

?>

Como veis, podemos utilizar tanto las llaves típicas como también los dos puntos y la sentencia final ENDFOR para indicar el fin de las instrucciones que debe ejecutar el bucle.

Avanzado
PHP nos deja hacer cosas más raras con las expresiones del bucle, como por ejemplo dejarlas vacías y entrar en un bucle infinito que acabaríamos rompiendo con un break. Puede que alguien le encuentre alguna utilidad concreta, sin embargo en mi caso nunca lo he definido así.

Bucle FOR utilizando arrays

Evidentemente, nuestras estructuras de control en PHP van a utilizar en la mayoría de ocasiones los arrays para recorrerlos, pues es prácticamente su utilidad más básica. Veamos un ejemplo antes de fijarnos en un pequeño pero gran detalle.

<?php

$frutas = array('manzana', 'pera', 'platano', 'cereza');

for ($i = 0; $i < count($frutas); $i++) {
  echo 'La fruta ' . $i . ' es ' . $frutas[$i] . '<br>';
}

?>

Tenemos un pequeño programa que tiene un array de frutas. Utilizamos un FOR que empieza con $i valiendo 0 y se ejecuta hasta que $i sea menor que la longitud de $frutas, es decir, en este caso hasta que sea menor que 4. Por tanto, se ejecutará con valores 0, 1, 2 y 3 accediendo así a $frutas[0], $frutas[1], $frutas[2] y $frutas[3] cuando estemos mostrando por pantalla la fruta en la que estamos. Nunca llegará a $frutas[4], que no existe, porque nuestra condición es que sea menor que el tamaño del array, no igual.

Con arrays enormes, resultados enormes

Este código funciona perfectamente y no da problemas. Sin embargo, podemos mejorar su eficiencia. Debemos fijarnos que, en cada iteración, el bucle consulta la condición $i < count($frutas) para decidir si debe continuar o no. Ésto provoca que, cada vez, tengamos que forzar al programa a calcular, de nuevo, el tamaño del array $frutas.

En este ejemplo puede parecer algo que no hace falta tener en cuenta, pero, ¿y si tuviéramos un array de 100 millones de registros? A la hora de recorrer el array, estaríamos pidiéndole que calculara de nuevo el tamaño del array. Pongamos, por ejemplo y sin pensar si me estoy pasando o quedando corto, que le cuesta 0.000001 segundos contar cada elemento del array, así 100 millones tardarían 100 segundos en ser contados. 100 segundos equivalen a 1 minuto y 40 segundos que necesita para contar esos 100 millones de registros.

Ahora nos ponemos a recorrer el array de 100 millones de registros y, en cada iteración, volvemos a calcular el tamaño, tardando otro minuto y 40 segundos. Y ese tiempo por 100 millones de registros nos da un resultado de 10000 millones de segundos, o sea, 10000000000 segundos. ¿Cuánto es esa cantidad de segundos en… minutos, horas, días? No, esa cantidad de segundos equivale a más de 3 siglos. Una auténtica locura para simplemente contar un array.

Curiosidad
Hay estudios para todo como, por ejemplo, éste estudio en el que se plantearon cuánto nos costaría a las personas contar un millon, un billón o un trillón de números. En base a un número de sílabas por segundo (hay un pequeño contador en ese enlace para que veas cuánto tiempo tardas en contar hasta 20), e introduciendo cuántas horas puedes contar al día, te da un resultado de cuánto tardarías.

Por ejemplo, en nuestro caso hemos contado a unas 7 sílabas por segundo y hemos colocado que podemos contar las 24 horas del día, como si fuéramos un ordenador que no parara nunca. Pues bien, nos costaría 21.8 días contar hasta un millón, 94.2 años contar hasta un billón y la friolera de 128624 años para contar hasta un trillón.

En el caso en que, por ejemplo, fuéramos capaces de contar a 100 sílabas por segundo tardaríamos día y medio en contar hasta un millón, 6 años y medio en contar hasta un billón y algo más de 9003 años para contar hasta un trillón. Tendríamos que llegar a contar a 1000 millones de sílabas por segundos para que contar hasta un trillón nos ocupara “sólo” 8 horas.

Mejorando la eficiencia

Así pues, vamos a mejorar la eficiencia de este simple programita. ¿Cómo? Pues calculando una y sólo una vez el tamaño del array.

<?php

$frutas = array('manzana', 'pera', 'platano', 'cereza');

$longitud_frutas = count($frutas)
for ($i = 0; $i < $longitud_frutas; $i++) {
  echo 'La fruta ' . $i . ' es ' . $frutas[$i] . '<br>';
}

?>

De esta forma, hemos conseguido contar los elementos del array una vez, guardar ese número en $longitud_frutas y luego recorrer el array. La condición ahora sólo consulta ese número en la variable y no la vuelve a calcular. Hemos ganado en eficiencia. Aún así, contar de uno en uno arrays enormes siempre va a suponer un gasto de tiempo enorme.

Utilización de FOREACH

En cuanto a la utilización de FOREACH veremos que tampoco tiene un gran misterio, aunque nos interesará saber cómo acceder al índice del array, algo muy útil en determinadas situaciones. FOREACH viene maravillosamente bien para recorrer arrays sin tener que contar los elementos que tienen. De esta forma, podemos evitar lo que nos ocurría con el FOR, e incluso evitar el error que hace que nos podamos pasar de un elemento o no.

Con FOREACH viene también la palabra AS para definir, a continuación, el elemento que estamos recorriendo. Su sintaxis muestra que, entre paréntesis, colocamos el array a recorrer, la palabra AS y el nombre de variable que queremos utilizar para un elemento individual. Vamos a verlo con ejemplos.

<?php

$precio_frutas = array(
  'manzana' => 1.21,
  'pera' => 0.92,
  'platano' => 1.65,
  'cereza' => 2.07
);

foreach ($precio_frutas as $precio_fruta) {
  echo 'El precio de la fruta es ' . $precio_fruta .'<br>';
}

?>

En este ejemplo, mostramos por pantalla los cuatro precios de las frutas. Sin embargo, aunque es totalmente funcional y correto, no sabemos a qué precio corresponde cada fruta, lo cual a veces necesitamos. Vamos a definir ahora un índice externo como si fuera el FOR.

<?php

$precio_frutas = array(
  'manzana' => 1.21,
  'pera' => 0.92,
  'platano' => 1.65,
  'cereza' => 2.07
);

$i = 1;
foreach ($precio_frutas as $precio_fruta) {
  echo 'El precio de la fruta ' . $i . ' es ' . $precio_fruta .'<br>';
  $i++;
}

?>

Ahora tenemos un índice, por lo que mostraremos por pantalla “El precio de la fruta 1 es 1.21”, luego “El precio de la fruta 2 es 0.92”, etc. Pero, aunque útil, queda un poco irrelevante en este ejemplo. ¿Cuál es la fruta 1? Además, estamos perdiendo la flexibilidad del FOREACH, pues hemos tenido que definir un índice antes e incrementarlo dentro. Para eso, mejor utilizar un FOR.

Utilizando los índices dentro del FOREACH

Por ello, vamos a utilizar la sintaxis que tenemos en el FOREACH para acceder a los índices también. Se utiliza el símbolo => como vemos a continuación.

<?php

$precio_frutas = array(
  'manzana' => 1.21,
  'pera' => 0.92,
  'platano' => 1.65,
  'cereza' => 2.07
);

foreach ($precio_frutas as $fruta => $precio_fruta):
  echo 'El precio de la fruta ' . $fruta . ' es ' . $precio_fruta .'<br>';
endforeach;

?>

Ahora mucho mejor. Por pantalla mostraremos “El precio de la fruta manzana es 1.21”. Posteriormente la siguiente fruta, luego otra más y así hasta terminar. Gracias a este método, podemos guardar dos datos en nuestros arrays con índice personalizado. Un valor que utilizamos como identificador, y otro que corresponde al valor del elemento.

Por último, vemos que también podemos indicarlo con los dos puntos y la palabra final ENDFOREACH al igual que las demás estructuras de control.

Conclusión

Cerramos así las principales estructuras de control en PHP. Hemos visto cómo utilizar IF, ELSE como condicionales y WHILE, FOR y FOREACH como iterativos. Ahora podemos enriquecer nuestros programas con condiciones y recorriendo conjuntos de elementos.

Tenemos las herramientas más básicas para la construcción de nuestros programas. Por una parte, podríamos decir que tenemos lo fundamental, pues todo lo siguiente que veamos son construcciones para mejorar la forma de programar. Pero me atrevería a decir que con los tipos de datos elementales, los principales operadores y las estructuras de control vistas, podemos construir la mayoría de programas. Eso sí, el código sería muchas veces largo, difícil y propenso a errores.

Por ello, en próximos artículos comenzaremos a ver qué son las funciones. Pero, antes, mejor detenerse un poquito en errores típicos con los bucles y en un nuevo reto con A practicar…. Pero ya estamos en el punto de partida para poder crear muchas cosas.

Deja un comentario