Imagina que necesitas imprimir una tabla de datos, o que necesitas agrupar multiples valores o validar una gran cantidad de datos y filtrar solo los necesarios, hacer cualquiera de estas operaciones u otras operaciones similares conllevarían repetir muchas lineas de código idénticas, pongamos una tabla de datos para ejemplificar:
$staff = [
[
"name" => "Maria",
"email" => "maria@test.test",
"role" => "administrator",
],
[
"name" => "Luis",
"email" => "luis@test.test",
"role" => "marketing",
],
// ...
[
"name" => "Cris",
"email" => "cris@test.test",
"role" => "producer",
],
];
Imprimir una tabla con estos datos conllevaría un código interminable que dependería de la cantidad de datos, por ejemplo:
echo "{$staff[0]['name']} - {$staff[0]['email']} - {$staff[0]['role']}<br>";
echo "{$staff[1]['name']} - {$staff[1]['email']} - {$staff[1]['role']}<br>";
// ...
echo "{$staff[2]['name']} - {$staff[2]['email']} - {$staff[2]['role']}<br>";
Para este tipo de casos es que existen las estructuras repetitivas, así que apliquemos una de ellas a este ejemplo y veamos como se simplifica el código:
foreach($staff as $person){
echo "{$person['name']} - {$person['email']} - {$person['role']}<br>";
}
Si reproduces el código obtendrás la siguiente respuesta:
Luis - luis@test.test - marketing
Cris - Cris@test.test - producer
Para repetir instrucciones relacionadas con arreglos en PHP tenemos el bucle foreach y es la estructura repetitiva más simple y efectiva para trabajar con listas y tablas de datos.
El bucle foreach permite repetir una o varias instrucciones por cada elemento dentro de un arreglo.
La sintaxis de este bucle es muy simple, solo se escribe foreach y entre paréntesis indicamos cual es el arreglo a iterar seguido de la palabra "as", luego una variable que servirá de alías para acceder al elemento que el bucle esta accediendo en ese momento y finalmente entre llaves indicaremos las instrucciones a repetir en cada ciclo del bucle.
Acceso a las llaves de un arreglo
El bucle foreach nos permite también acceder a las llaves del arreglo, conociendo la llave podemos usarla para añadir mas información útil añadiendo una dimensión extra de datos, ademas de que es necesario poder acceder a la llave para poder modificar los elementos dentro del arreglo.
Para acceder a la llave hay que indicarla en el bucle con una variable alias seguida del operador "=>" (flecha doble) quedando de la siguiente forma:
foreach($arreglo as $clave => $valor){
// Instrucciones a repetir en cada ciclo ...
}
Veamos un ejemplo para dejarlo claro...
$days = [
1 => 'domingo',
2 => 'lunes',
3 => 'martes',
4 => 'miércoles',
5 => 'jueves',
6 => 'viernes',
7 => 'sábado',
];
foreach($days as $dayNumber => $dayName){
echo "{$dayNumber} - {$dayName}<br>";
}
2 - lunes
3 - martes
4 - miércoles
5 - jueves
6 - viernes
7 - sábado
Este es un arreglo típico en el que tenemos una lista de opciones numerada, donde el número de la opción si que es importante y es un dato que nos interesa conocer.
Ahora veamos como recorrer una tabla de datos anidando bucles foreach, para este ejemplo usaremos una tabla de datos de usuarios y vamos a imprimirla en forma de una tabla HTML.
$users = [
[
'id' => 3200,
'name' => 'Juan Perez',
'email' => 'juan@app.test',
'status' => 1,
],
[
'id' => 3201,
'name' => 'Cris Rodriguez',
'email' => 'cris@app.test',
'status' => 0,
],
[
'id' => 3202,
'name' => 'Luis Hernández',
'email' => 'Luis@app.test',
'status' => 1,
],
[
'id' => 3203,
'name' => 'Juana Alvarez',
'email' => 'juana@app.test',
'status' => 1,
],
];
echo "<table>";
foreach($users as $user){
echo "<tr>";
foreach($user as $property => $value){
echo "<td><strong>{$property}</strong>: {$value}</td>";
}
echo "</tr>";
}
echo "</table>";
id: 3200 | name: Juan Perez | email: juan@app.test | status: 1 |
id: 3201 | name: Cris Rodriguez | email: cris@app.test | status: 0 |
id: 3202 | name: Luis Hernández | email: Luis@app.test | status: 1 |
id: 3203 | name: Juana Alvarez | email: juana@app.test | status: 1 |
Saltar instrucciones dentro de un bucle
Para saltar ciclos completos o instrucciones especificas dentro de un bucle tenemos la instrucción continue;, la cual le dice a PHP que salte al siguiente ciclo sin importar que otras instrucciones estuvieran después.
Para ejemplificarlo vamos a recorrer el mismo arreglo de hace un momento, pero vamos a hacer que salte a los usuarios con los id 3201 y 3202:
echo "<table>";
foreach($users as $user){
if($user['id'] == 3201 || $user['id'] == 3202){
continue;
}
echo "<tr>";
foreach($user as $property => $value){
echo "<td><strong>{$property}</strong>: {$value}</td>";
}
echo "</tr>";
}
echo "</table>";
id: 3200 | name: Juan Perez | email: juan@app.test | status: 1 |
id: 3203 | name: Juana Alvarez | email: juana@app.test | status: 1 |
Detener la ejecución de un bucle
Para poder detener por completo un bucle usamos la instrucción break;
Para ver como se detiene una estructura repetitiva un bucle hagamos que el bucle solo imprima hasta el usuario del id 3201:
echo "<table>";
foreach($users as $user){
echo "<tr>";
foreach($user as $property => $value){
echo "<td><strong>{$property}</strong>: {$value}</td>";
}
echo "</tr>";
if ($user['id'] == 3201) {
break;
}
}
echo "</table>";
id: 3200 | name: Juan Perez | email: juan@app.test | status: 1 |
id: 3201 | name: Cris Rodriguez | email: cris@app.test | status: 0 |
Bucle For
Este bucle repetirá las instrucciones indicadas hasta que se deje cumplir una condición dada.
El bucle For se utiliza cuando se quieren repetir las instrucciones deseadas una cantidad especifica de veces.
Para usar el bucle for es necesario saber que este se compone de varias partes, primero en su definición tenemos 3 secciones:
- Inicialización: Se definen una o multiples variables antes de empezar con el bucle, normalmente aquí se define un valor para llevar la cuenta de cuantas veces se ha ejecutado el bucle
- Evaluación: Se evalúa una condición en cada ciclo para determinar si el bucle debe continuar una vez más o detenerse
- Cambio con cada ciclo: Se cambia algún valor en cada ciclo, lo normal suele ser cambiar el valor de la variable que lleva la variable definida en un inicio que lleva la cuenta.
Suena mas complicado de lo que realmente es, veamos como quedaría finalmente el bucle for:
for($i=1; $i<=10; $i++){
echo "{$i}<br>";
}
Si corremos este trozo de código el bucle imprimirá los números del 1 al 10.
La variable $i sirve para definir un valor inicial que llevara la cuenta, luego tenemos la condición que mientras $i sea menor o igual a diez el bucle debe repetir la instrucción definida y en cada ciclo debe aumentar en uno el valor de $i y finalmente la instrucción a repetir es la de imprimir el valor que lleva la cuenta.
Veamos otro ejemplo, en un sitio donde se tiene cierta cantidad de elementos y se desea paginar esos elementos, sabiendo la cantidad de paginas existentes (13 por ejemplo), usando el bucle for podemos generar la paginación de forma simple:
for($i=1; $i<=13; $i++){
echo "<a href=\"http://localhost/app?page={$i}\">{$i}</a> ";
}
Iterar arreglos con el bucle For
El bucle for se puede usar también para recorrer arreglos simples, de hecho en otros lenguajes de programación el bucle for es el modo estándar para iterar sobre arreglos.
¿Pero en PHP que sentido tendría usar el bucle for sobre el mas simple y cómodo bucle foreach?
Pues con el bucle for podemos iterar arreglos sin tener que empezar por el inicio, podemos por ejemplo recorrerlos en reversa.
Veamos el ejemplo anterior de imprimir un arreglo con los días de la semana pero ahora en reversa:
$days = [
1 => 'domingo',
2 => 'lunes',
3 => 'martes',
4 => 'miércoles',
5 => 'jueves',
6 => 'viernes',
7 => 'sábado',
];
for($i = 7; $i>0; $i--){
echo "{$i} - {$days[$i]}<br>";
}
6 - viernes
5 - jueves
4 - miércoles
3 - martes
2 - lunes
1 - domingo
Hay que poner mucha atención a la condición del bucle y al valor que se cambia en cada ciclo, si el valor no se cambiase correctamente el ciclo no terminaría y se ejecutaría infinitamente (ó hasta que el motor de php alcance el límite de memoria asignado.) y si la condición es incorrecta el bucle podría no ejecutarse o podría ejecutarse menos o más veces de las esperadas.
El bucle while
Esta estructura repetitiva permite ejecutar multiples veces las instrucciones que agrupa en su interior mientras se cumpla una condición dada, la cual se evalúa en cada repetición. Este bucle tiene la siguiente sintaxis:
while($condicion){
// Instrucciones a repetir...
}
El bucle while es más sencillo pero más flexible que los bucles anteriores.
Iterar arreglos con el bucle While
al igual que los bucles anteriores puede usarse para recorrer arreglos, aunque lo mas fácil sería recorrerlos con foreach o con for, pero veamos como sería para entender la sintaxis de este bucle.
$colors = ['red', 'green', 'blue'];
$i = 0;
while($i < 3){
echo "{$colors[$i]}<br>";
$i++;
}
Al igual que con el bucle for, para recorrer arreglos tendríamos que definir una variable que lleve la cuenta, luego debemos definir la condición que se evaluara para saber si el ciclo debe continuar o no y por último debemos incrementar el valor de la variable que lleva la cuenta, pero de estas tres cosas ninguna forma parte del bucle propiamente.
Para que veas a a que me refiero veamos un bucle while sin una condición que evaluar:
$colors = ['red', 'green', 'blue'];
$i = 0;
while (true) {
echo "{$colors[$i]}<br>";
$i++;
if($i >= 3){
break;
}
}
El bucle while puede simplemente usarse pasándole el valor booleano true para que se ejecute indefinidamente, pero para que no de lugar a un bucle infinito dentro de las instrucciones del bucle podemos evaluar cuando debería detenerse y usar la instrucción break para finalizar el bucle.
Para ejemplificar un bucle que se ejecuta indefinidamente veamos un algoritmo muy común
Este algoritmo se usa para generar una lista de horarios de disponibilidad (pueden ser horarios de atención en un consultorio, horarios estimados de salida y llegada para una ruta de algún transporte, espacios de alquiler de un aula o un local, etc.)
El código sería el siguiente y en seguida lo desgranaremos:
$startingHour = 8;
$endingHour = 10;
$duration = 40;
$slots = [];
$slotHour = $startingHour;
$slotMinute = 0;
while (true) {
$slots[] = [
'hour' => $slotHour,
'minute' => $slotMinute
];
$slotMinute += $duration;
if ($slotMinute >= 60) {
$slotMinute -= 60;
$slotHour++;
}
if ($slotHour >= $endingHour) {
break;
}
}
echo "<h3>Horarios disponibles</h3>";
echo "<ul>";
foreach ($slots as $time) {
if (0 == $time['minute']) {
$time['minute'] = '00';
}
echo "<li>{$time['hour']}:{$time['minute']}</li>";
}
echo "</ul>";
Horarios disponibles
- 8:00
- 8:40
- 9:20
- 10:00
- 10:40
- 11:20
- 12:00
- 12:40
- 13:20
Lo primero es empezar definiendo 3 valores iniciales necesarios para el funcionamiento, la hora de inicio, la hora de finalización y la duración (en minutos) o tiempo separación entre disponibilidades.
Después tenemos el arreglo que almacenara la lista de horarios disponibles seguido de dos valores que llevan la cuenta de la hora y minuto que irán cambiando con cada ciclo.
Luego tenemos nuestro bucle while que se ejecutara indefinidamente
Dentro del bucle tenemos la instrucción de guardar el horario en cada iteración, el cual ira cambiando en intervalos definidos por la duración establecida.
En seguida tenemos el calculo del tiempo, en el que se suma la variable con la duración a la variable que lleva la cuenta de los minutos y por cada 60 minutos que se completen, se debe volver a empezar en cero los minutos y se debe incrementar en uno la variable que lleva la cuenta de las horas.
Por ultimo dentro del bucle tenemos la condición que detendrá la ejecución del bucle para evitar que siga calculando horarios infinitamente.
En cuanto el valor que lleva la cuenta de las horas alcance al valor de la hora de finalización detenemos el ciclo.
Ahora simplemente imprimimos en HTML una lista con los horarios que generamos usando un bucle foreach.