PHP básico

Arreglos y funciones

Lección 4 de 8 · 15 min

Doce artículos, ¿doce variables?

Un pedido trae doce artículos. Con lo que sabes hasta ahora harían falta $articulo1, $articulo2… hasta doce, y habría que reescribir el programa entero el día que alguien pida trece.

La solución es el arreglo: una sola variable que guarda muchos valores, uno detrás de otro, y que crece o se encoge sin que tú toques el código.

Un arreglo de toda la vida
<?php
$servicios = ['Soporte', 'Mantenimiento', 'Licenciamiento'];

echo $servicios[0];
echo "\n";
echo count($servicios) . ' servicios';
Resultado
Soporte
3 servicios

El primer elemento es el 0, no el 1. En un arreglo de tres, las posiciones son 0, 1 y 2. Pedir la [3] no devuelve el último: devuelve un aviso y nada.

Se llama contar desde cero y es así en casi todos los lenguajes. Al principio incomoda; a la semana ya no lo piensas.

El arreglo que se lee: claves con nombre

Recordar que la posición 3 era el teléfono es tan malo como no guardarlo. Por eso el arreglo que más vas a usar no se numera: cada valor lleva un nombre, y se llama arreglo asociativo.

Esta es exactamente la forma en la que te va a llegar un formulario y una fila de la base de datos, así que vale la pena mirarlo con calma:

Un cliente, con sus datos con nombre
<?php
$cliente = [
    'nombre'   => 'Ana Gómez',
    'ciudad'   => 'Bogotá',
    'telefono' => '3001234567',
    'activo'   => true,
];

echo $cliente['nombre'] . ' - ' . $cliente['ciudad'];

// Dentro de comillas dobles hay que poner llaves:
echo "\nCliente: {$cliente['nombre']}";
Resultado
Ana Gómez - Bogotá
Cliente: Ana Gómez

Ese detalle de las llaves es de los que hacen perder media hora la primera vez. Dentro de comillas dobles, {$cliente['nombre']} funciona y sin las llaves es un error de sintaxis. Con comillas simples y un punto, como en la primera línea, no hay problema nunca.

Recorrerlo entero: foreach

Aquí es donde el arreglo se paga solo. foreach pasa por todos los elementos, sean tres o trescientos, sin que tú sepas cuántos hay:

foreach, de las dos formas
<?php
$servicios = ['Soporte', 'Mantenimiento', 'Licenciamiento'];

foreach ($servicios as $servicio) {
    echo '- ' . $servicio . "\n";
}

$cliente = ['nombre' => 'Ana Gómez', 'ciudad' => 'Bogotá'];

foreach ($cliente as $campo => $valor) {
    echo $campo . ': ' . $valor . "\n";
}
Resultado
- Soporte
- Mantenimiento
- Licenciamiento
nombre: Ana Gómez
ciudad: Bogotá

$servicio y $valor son nombres que eliges tú: son la caja donde foreach deja el elemento de esta vuelta. La versión con => te da también la clave, que es lo que necesitas cuando el arreglo tiene nombres.

Lo que de verdad vas a manejar: una lista de fichas

Junta las dos ideas y tienes la estructura con la que se construye media web: un arreglo de arreglos. Una lista de productos donde cada producto es una ficha con sus campos.

La tabla de precios de una página real
<?php
$productos = [
    ['nombre' => 'Teclado',  'precio' => 89000,  'existencias' => 12],
    ['nombre' => 'Monitor',  'precio' => 650000, 'existencias' => 0],
    ['nombre' => 'Diadema',  'precio' => 120000, 'existencias' => 3],
];

foreach ($productos as $p) {
    $estado = $p['existencias'] === 0 ? 'Agotado' : 'Disponible';
    echo $p['nombre'] . ' - $' . number_format($p['precio'], 0, ',', '.')
        . ' - ' . $estado . "\n";
}
Resultado
Teclado - $89.000 - Disponible
Monitor - $650.000 - Agotado
Diadema - $120.000 - Disponible

Esa línea del $estado usa el operador ternario: condición ? valor si sí : valor si no. Es un if de una sola línea, y se usa mucho para elegir un texto. Cuando la lógica crece, vuelve al if normal: legible gana a corto.

Funciones: escribirlo una vez

Mira el ejemplo anterior. El formato del precio -number_format con sus tres argumentos- va a repetirse en la ficha, en el carrito, en el correo de confirmación y en la factura. Cuatro sitios.

El día que el negocio pida mostrar los decimales, hay que acordarse de los cuatro. Y no se acuerda: se corrigen tres y el cuarto queda mal durante meses. Por eso lo que se repite se encierra en una función.

Una función: entra un dato, sale un resultado
<?php
function formatearPrecio(int $valor): string
{
    return '$' . number_format($valor, 0, ',', '.');
}

echo formatearPrecio(89000);
echo "\n";
echo formatearPrecio(650000);
Resultado
$89.000
$650.000

Las cuatro partes de una función

  1. El nombre

    formatearPrecio. Que diga qué hace, en verbo. Si no sabes cómo llamarla, suele ser señal de que hace dos cosas y deberían ser dos funciones.

  2. Lo que recibe

    (int $valor): los datos con los que trabaja. El int es opcional pero conviene: le dice a PHP que ahí entra un número, y si le llega otra cosa avisa en vez de calcular mal en silencio.

  3. Lo que devuelve

    : string anuncia que devuelve texto, y return es la línea que lo entrega.

    return además termina la función ahí mismo: lo que haya debajo no se ejecuta.

  4. El cuerpo

    Lo que hace, entre llaves. Una función corta que se entiende de una lectura vale más que una larga que lo hace todo.

Dentro de una función no existen las variables de fuera. Es la causa del «undefined variable» más frecuente al empezar: escribes una función que usa $productos y no funciona, aunque $productos esté definida tres líneas arriba.

No es un fallo, es la gracia del asunto: una función es una caja cerrada que solo conoce lo que le pasas como argumento. Eso es lo que permite usarla en cualquier página sin sorpresas.

Valores por defecto: un argumento opcional
<?php
function formatearPrecio(int $valor, int $decimales = 0): string
{
    return '$' . number_format($valor, $decimales, ',', '.');
}

echo formatearPrecio(89000);
echo "\n";
echo formatearPrecio(89000, 2);
Resultado
$89.000
$89.000,00

Ahora la función sirve para los dos casos y las páginas que ya la usaban no se enteran del cambio. Los argumentos con valor por defecto van siempre al final de la lista.

Funciones que ya vienen hechas y vas a usar mucho

Para arreglos

count() cuántos hay · in_array() si un valor está · array_keys() las claves · sort() ordena · array_sum() suma los valores.

implode(', ', $lista) convierte el arreglo en un texto separado por comas, que es lo que se necesita para mostrarlo.

Para texto

trim() quita espacios sobrantes de los extremos -en un formulario, imprescindible- · strlen() longitud · strtolower() a minúsculas · str_replace() reemplaza.

¿Cómo sé qué argumentos lleva una función?

Se mira en php.net. La documentación oficial de cada función trae su firma, cada parámetro explicado y ejemplos, y está traducida al español en buena parte.

Es una costumbre que separa a quien avanza de quien se atasca: los argumentos no se adivinan, se miran.

Qué usarías en cada caso

Arrastra la función a la situación que resuelve, o toca la función y luego su espacio.

  1. Mostrar «Tienes 3 artículos en el carrito» sin saber de antemano cuántos hay.
  2. El visitante escribió su correo con un espacio al final y hay que quitarlo antes de guardarlo.
  3. Comprobar si la ciudad que eligió está dentro de las que tienen domicilio.
  4. Convertir la lista de servicios contratados en una sola línea separada por comas para el correo.
  5. Mostrar 650000 como 650.000 en la ficha del producto.

Compruébalo tú mismo

Tienes $dias = ['lunes', 'martes', 'miércoles']; ¿Qué devuelve $dias[1]?

Escribes una función que usa $productos, definida antes en la página, y sale «undefined variable». ¿Por qué?

El formato del precio está copiado en cuatro páginas y piden cambiarlo. ¿Cuál es el problema de fondo?

Lo que sigue

Ya sabes guardar, recorrer y reutilizar. Hasta ahora todos los datos los escribías tú dentro del archivo. En la siguiente lección los escribe el visitante, y eso cambia todo: hay que recibirlos, no fiarse de ellos y comprobarlos en el servidor.

Siguiente: Formularios: recibir y validar en el servidor

Continuar ← Decidir y repetir