Módulo 05: Arrays

Objetivos del módulo

  • Comprender qué es un array en PHP y por qué es la estructura de datos más usada
  • Crear arrays indexados, asociativos y multidimensionales
  • Añadir, modificar y eliminar elementos
  • Recorrer arrays de distintas formas
  • Dominar las funciones esenciales de arrays
  • Ordenar arrays con las funciones nativas y con criterios personalizados
  • Usar funciones de orden superior: array_map(), array_filter(), array_reduce() y array_walk()
  • Aprovechar las novedades de PHP 8.4 (array_find(), array_any(), array_all()…) y PHP 8.5 (array_first(), array_last())
  • Desestructurar arrays en variables
  • Usar arrays como pilas y colas

1. ¿Qué es un array?

📘 Concepto: Un array es una variable que guarda varios valores organizados como pares clave → valor. Si una variable normal es una caja, un array es una cajonera: cada cajón tiene una etiqueta (la clave) y un contenido (el valor).

En PHP, los arrays son extraordinariamente versátiles: el mismo tipo array sirve como lista, diccionario, pila, cola, tabla o árbol. Por eso los encontrarás en todas partes: los datos de un formulario ($_POST), las filas de una consulta a la base de datos, la configuración de una aplicación, la respuesta de una API en JSON…

Tipo de array Claves Ejemplo
Indexado (lista) Números enteros automáticos: 0, 1, 2… ['rojo', 'verde', 'azul']
Asociativo (diccionario) Cadenas que tú eliges ['nombre' => 'Ana', 'edad' => 30]
Multidimensional Arrays dentro de arrays [['id' => 1], ['id' => 2]]

📘 Concepto: Técnicamente, en PHP todos los arrays son mapas ordenados: conservan el orden en que se insertan los elementos y sus claves pueden ser enteros o cadenas. Un array “indexado” es simplemente uno cuyas claves son 0, 1, 2… consecutivas.


2. Crear arrays

Sintaxis [] frente a array()

<?php

declare(strict_types=1);

// Sintaxis corta (PHP 5.4+): la recomendada
$colores = ['rojo', 'verde', 'azul'];

// Sintaxis antigua: equivalente, la verás en código heredado
$colores = array('rojo', 'verde', 'azul');

// Array vacío
$carrito = [];

💡 Consejo: Usa siempre []. Es más corta, más legible y la que recomiendan los estándares actuales. array() solo aparece en código antiguo.

Arrays indexados

<?php

declare(strict_types=1);

$dias = ['lunes', 'martes', 'miércoles', 'jueves', 'viernes'];

echo $dias[0] . PHP_EOL;   // lunes   ← ¡el primer índice es 0!
echo $dias[4] . PHP_EOL;   // viernes
echo count($dias) . PHP_EOL; // 5

// Índice que no existe
echo $dias[10];   // Warning: Undefined array key 10

Arrays asociativos

Las claves se definen con =>:

<?php

declare(strict_types=1);

$libro = [
    'titulo' => 'Cien años de soledad',
    'autor' => 'Gabriel García Márquez',
    'anio' => 1967,
    'disponible' => true,
];

echo $libro['titulo'] . PHP_EOL;   // Cien años de soledad
echo "Publicado en {$libro['anio']}" . PHP_EOL;   // Publicado en 1967

💡 Consejo: Deja una coma tras el último elemento cuando escribas un array en varias líneas (trailing comma). Al añadir un elemento nuevo, solo cambia una línea y evitas errores por olvidar la coma.

Arrays multidimensionales

Un array puede contener otros arrays. Así se representan tablas, árboles o estructuras JSON:

<?php

declare(strict_types=1);

// Tabla: lista de filas (como el resultado de una consulta SQL)
$alumnos = [
    ['nombre' => 'Irene', 'curso' => '1º DAW', 'notas' => [8, 7.5, 9]],
    ['nombre' => 'Jorge', 'curso' => '2º DAW', 'notas' => [6, 5, 7]],
];

echo $alumnos[0]['nombre'] . PHP_EOL;     // Irene
echo $alumnos[1]['notas'][2] . PHP_EOL;   // 7

// Matriz 3x3
$matriz = [
    [1, 2, 3],
    [4, 5, 6],
    [7, 8, 9],
];

echo $matriz[1][2] . PHP_EOL;   // 6 (fila 1, columna 2)

Crear arrays con funciones: range()

<?php

print_r(range(1, 5));          // [1, 2, 3, 4, 5]
print_r(range(0, 20, 5));      // [0, 5, 10, 15, 20]
print_r(range('a', 'e'));      // ['a', 'b', 'c', 'd', 'e']
print_r(range(10, 1, 3));      // [10, 7, 4, 1]  - también descendente

3. Añadir, modificar y eliminar elementos

Añadir y modificar

<?php

declare(strict_types=1);

$frutas = ['manzana', 'pera'];

$frutas[] = 'kiwi';          // Añade al final (clave 2)
$frutas[0] = 'fresa';        // Modifica el elemento 0

$persona = ['nombre' => 'Raúl'];
$persona['email'] = 'raul@ejemplo.es';   // Añade una clave nueva
$persona['nombre'] = 'Raúl Gómez';       // Modifica una clave existente

print_r($frutas);    // [fresa, pera, kiwi]
print_r($persona);   // [nombre => Raúl Gómez, email => raul@ejemplo.es]

Funciones para añadir y quitar por los extremos

Función Qué hace Devuelve
array_push($a, ...$valores) Añade al final El nuevo número de elementos
array_pop($a) Quita el último El elemento quitado (o null si está vacío)
array_unshift($a, ...$valores) Añade al principio (reindexa) El nuevo número de elementos
array_shift($a) Quita el primero (reindexa) El elemento quitado (o null)
<?php

declare(strict_types=1);

$cola = ['Ana', 'Luis'];

array_push($cola, 'Marta', 'Pablo');   // [Ana, Luis, Marta, Pablo]
$ultimo = array_pop($cola);            // $ultimo = 'Pablo' → [Ana, Luis, Marta]
array_unshift($cola, 'Zoe');           // [Zoe, Ana, Luis, Marta]
$primero = array_shift($cola);         // $primero = 'Zoe' → [Ana, Luis, Marta]

echo implode(', ', $cola);             // Ana, Luis, Marta

💡 Consejo: Para añadir un elemento al final, $array[] = $valor; es más rápido y legible que array_push(). Reserva array_push() para añadir varios a la vez.

Eliminar con unset()

<?php

$numeros = [10, 20, 30, 40];
unset($numeros[1]);

print_r($numeros);
// Array ( [0] => 10 [2] => 30 [3] => 40 )   ← ¡el índice 1 ha desaparecido, no se reindexa!

$numeros = array_values($numeros);   // Reindexa: [0 => 10, 1 => 30, 2 => 40]

$config = ['debug' => true, 'cache' => false];
unset($config['debug']);             // Elimina una clave asociativa

⚠️ Importante: unset() deja “huecos” en los índices. Si después recorres el array con un for ($i = 0; $i < count($a); $i++), accederás a índices que no existen. Usa foreach o reindexa con array_values().


4. Recorrer arrays

<?php

declare(strict_types=1);

$stock = ['camisetas' => 25, 'pantalones' => 0, 'gorras' => 12];

// 1. foreach con valor (la forma más habitual)
foreach ($stock as $unidades) {
    echo $unidades . ' ';
}
echo PHP_EOL;   // 25 0 12

// 2. foreach con clave y valor
foreach ($stock as $producto => $unidades) {
    $estado = $unidades > 0 ? "$unidades uds." : 'AGOTADO';
    echo "$producto: $estado" . PHP_EOL;
}

5. Funciones esenciales

PHP tiene más de 80 funciones para arrays. Estas son las que usarás a diario:

Función Qué hace Ejemplo Resultado
count($a) Número de elementos count([1, 2, 3]) 3
in_array($v, $a, true) ¿Contiene el valor? in_array(2, [1, 2], true) true
array_search($v, $a, true) Clave del valor (o false) array_search('b', ['a', 'b'], true) 1
array_key_exists($k, $a) ¿Existe la clave? (aunque valga null) array_key_exists('x', ['x' => null]) true
array_keys($a) Lista de claves array_keys(['a' => 1, 'b' => 2]) ['a', 'b']
array_values($a) Lista de valores (reindexada) array_values(['a' => 1, 'b' => 2]) [1, 2]
array_merge($a, $b) Une arrays array_merge([1], [2, 3]) [1, 2, 3]
[...$a, ...$b] Une con el operador spread [...[1], ...[2]] [1, 2]
array_slice($a, $inicio, $long) Extrae una porción (sin modificar) array_slice([1, 2, 3, 4], 1, 2) [2, 3]
array_splice($a, $inicio, $long, $nuevos) Quita/sustituye una porción (modifica) ver ejemplo —
array_combine($claves, $valores) Crea un array asociativo array_combine(['a', 'b'], [1, 2]) ['a' => 1, 'b' => 2]
array_flip($a) Intercambia claves y valores array_flip(['a' => 1]) [1 => 'a']
array_unique($a) Elimina duplicados (conserva claves) array_unique([1, 1, 2]) [0 => 1, 2 => 2]
array_column($a, $col, $indice) Extrae una columna ver ejemplo —
array_sum($a) / array_product($a) Suma / producto array_sum([1, 2, 3]) 6
array_reverse($a) Invierte el orden array_reverse([1, 2, 3]) [3, 2, 1]
array_fill($inicio, $n, $v) Crea un array relleno array_fill(0, 3, 'x') ['x', 'x', 'x']
array_key_first($a) / array_key_last($a) Primera / última clave array_key_last(['a' => 1, 'b' => 2]) 'b'
array_is_list($a) ¿Claves 0, 1, 2… consecutivas? (PHP 8.1) array_is_list([1 => 'a']) false
range($ini, $fin, $paso) Crea una secuencia range(1, 3) [1, 2, 3]
compact('a', 'b') Crea un array desde variables ver ejemplo —
extract($a) Crea variables desde un array ver ejemplo —

Buscar: in_array(), array_search() y array_key_exists()

<?php

declare(strict_types=1);

$roles = ['editor', 'autor', 'admin'];

var_dump(in_array('admin', $roles, true));      // bool(true)
var_dump(array_search('autor', $roles, true));  // int(1)
var_dump(array_search('lector', $roles, true)); // bool(false)

// ⚠️ Trampa: array_search puede devolver 0, que es "falso"
$posicion = array_search('editor', $roles, true);   // 0
if ($posicion !== false) {                           // ✅ Compara con !== false
    echo "Encontrado en la posición $posicion" . PHP_EOL;
}

⚠️ Importante: Pasa siempre true como tercer argumento de in_array() y array_search() para que comparen con ===. Sin él comparan con ==: in_array('1e1', ['10']) devuelve true, e in_array(0, ['a', null]) también (porque 0 == null).

Unir arrays: array_merge(), spread y +

<?php

declare(strict_types=1);

$basicos = ['pan', 'leche'];
$extra = ['café', 'galletas'];

print_r(array_merge($basicos, $extra));   // [pan, leche, café, galletas]
print_r([...$basicos, ...$extra]);        // Igual, con el operador spread
print_r([...$basicos, 'huevos', ...$extra]); // Puedes intercalar valores

// Con claves de texto, el último valor gana
$porDefecto = ['tema' => 'claro', 'idioma' => 'es', 'avisos' => true];
$usuario = ['tema' => 'oscuro'];

print_r(array_merge($porDefecto, $usuario));
// [tema => oscuro, idioma => es, avisos => 1]

print_r([...$porDefecto, ...$usuario]);   // Igual (claves de texto en spread desde PHP 8.1)

// El operador + conserva el valor del PRIMER array si la clave se repite
print_r($usuario + $porDefecto);
// [tema => oscuro, idioma => es, avisos => 1]
Forma Claves numéricas Claves de texto repetidas
array_merge($a, $b) Se renumeran (0, 1, 2…) Gana $b
[...$a, ...$b] Se renumeran Gana $b
$a + $b Se conservan; si se repiten, gana $a Gana $a

Porciones: array_slice() y array_splice()

<?php

declare(strict_types=1);

$ranking = ['Oro', 'Plata', 'Bronce', 'Cuarto', 'Quinto'];

// array_slice NO modifica el original
$podio = array_slice($ranking, 0, 3);    // [Oro, Plata, Bronce]
$ultimos = array_slice($ranking, -2);    // [Cuarto, Quinto] (negativo: desde el final)

// array_splice SÍ modifica el original y devuelve lo eliminado
$letras = ['a', 'b', 'c', 'd', 'e'];
$quitadas = array_splice($letras, 1, 2, ['X', 'Y', 'Z']);

print_r($quitadas);   // [b, c]
print_r($letras);     // [a, X, Y, Z, d, e]

Combinar, invertir y eliminar duplicados

<?php

declare(strict_types=1);

$codigos = ['ES', 'FR', 'PT'];
$paises = ['España', 'Francia', 'Portugal'];

$mapa = array_combine($codigos, $paises);
// [ES => España, FR => Francia, PT => Portugal]

$inverso = array_flip($mapa);
// [España => ES, Francia => FR, Portugal => PT]

$etiquetas = ['php', 'web', 'php', 'mysql', 'web'];
$sinRepetir = array_values(array_unique($etiquetas));
// [php, web, mysql]

Extraer columnas: array_column()

Imprescindible con datos tabulares:

<?php

declare(strict_types=1);

$usuarios = [
    ['id' => 7, 'nombre' => 'Clara', 'email' => 'clara@ejemplo.es'],
    ['id' => 12, 'nombre' => 'Diego', 'email' => 'diego@ejemplo.es'],
    ['id' => 15, 'nombre' => 'Eva', 'email' => 'eva@ejemplo.es'],
];

$nombres = array_column($usuarios, 'nombre');
// [Clara, Diego, Eva]

$emailsPorId = array_column($usuarios, 'email', 'id');
// [7 => clara@ejemplo.es, 12 => diego@ejemplo.es, 15 => eva@ejemplo.es]

$usuariosPorId = array_column($usuarios, null, 'id');
// [7 => [...Clara...], 12 => [...Diego...], 15 => [...Eva...]]

echo $usuariosPorId[12]['nombre'];   // Diego

compact() y extract()

<?php

declare(strict_types=1);

$titulo = 'Inicio';
$usuario = 'Marina';

// compact: de variables a array (muy usado al pasar datos a plantillas)
$datos = compact('titulo', 'usuario');
// ['titulo' => 'Inicio', 'usuario' => 'Marina']

// extract: de array a variables
extract(['color' => 'azul', 'talla' => 'M']);
echo "$color $talla";   // azul M

⚠️ Importante: Nunca uses extract() con datos del usuario (extract($_POST)): un atacante podría crear o sobrescribir cualquier variable ($esAdmin, $precio…). Igual que las variables de variables del módulo 02, extract() oculta de dónde salen las variables. Úsalo, como mucho, en motores de plantillas muy controlados.


6. Ordenar arrays

Funciones de ordenación

Función Ordena por Orden ¿Conserva las claves?
sort() Valor Ascendente ❌ Reindexa
rsort() Valor Descendente ❌ Reindexa
asort() Valor Ascendente ✅ Sí
arsort() Valor Descendente ✅ Sí
ksort() Clave Ascendente ✅ Sí
krsort() Clave Descendente ✅ Sí
usort() Función propia (valor) Personalizado ❌ Reindexa
uasort() Función propia (valor) Personalizado ✅ Sí
uksort() Función propia (clave) Personalizado ✅ Sí
natsort() Valor, orden “natural” Ascendente ✅ Sí

⚠️ Importante: Todas las funciones de ordenación modifican el array original (lo reciben por referencia) y devuelven true. No escribas $ordenado = sort($numeros);: $ordenado valdría true.

<?php

declare(strict_types=1);

$numeros = [42, 7, 19, 3, 25];
sort($numeros);
print_r($numeros);   // [3, 7, 19, 25, 42]

$edades = ['Lucas' => 34, 'Ana' => 28, 'Teo' => 41];

asort($edades);      // Por valor, conservando quién es quién
print_r($edades);    // [Ana => 28, Lucas => 34, Teo => 41]

ksort($edades);      // Por clave (nombre)
print_r($edades);    // [Ana => 28, Lucas => 34, Teo => 41]

Ordenación personalizada con usort() y <=>

usort() recibe una función que compara dos elementos y devuelve un número negativo, cero o positivo. El operador <=> del módulo 03 hace exactamente eso:

<?php

declare(strict_types=1);

$productos = [
    ['nombre' => 'Auriculares', 'precio' => 59.0, 'valoracion' => 4.5],
    ['nombre' => 'Altavoz', 'precio' => 35.0, 'valoracion' => 4.8],
    ['nombre' => 'Micrófono', 'precio' => 89.0, 'valoracion' => 4.5],
];

// Por precio ascendente
usort($productos, fn(array $a, array $b): int => $a['precio'] <=> $b['precio']);
echo implode(', ', array_column($productos, 'nombre')) . PHP_EOL;
// Altavoz, Auriculares, Micrófono

// Por valoración descendente y, a igualdad, por precio ascendente
usort($productos, fn(array $a, array $b): int =>
    [$b['valoracion'], $a['precio']] <=> [$a['valoracion'], $b['precio']]
);
echo implode(', ', array_column($productos, 'nombre')) . PHP_EOL;
// Altavoz, Auriculares, Micrófono

💡 Consejo: Comparar arrays con <=> compara elemento a elemento, así que [$a1, $a2] <=> [$b1, $b2] es una forma elegante de ordenar por varios criterios. Fíjate en que para el criterio descendente se intercambia $a por $b.

📘 Concepto: Desde PHP 8.0, la ordenación es estable: si dos elementos son “iguales” según tu criterio, mantienen el orden que tenían. Esto permite ordenar en varias pasadas sin perder la ordenación previa.


7. Funciones de orden superior

📘 Concepto: Una función de orden superior es una función que recibe otra función como argumento. En lugar de escribir un bucle, le dices a PHP qué hacer con cada elemento y él se encarga de recorrer el array. Es el estilo de programación funcional.

Las funciones que pasamos suelen ser arrow functions (fn($x) => ...), que verás a fondo en el módulo 07.

array_map(): transformar cada elemento

Aplica una función a cada elemento y devuelve un array nuevo con los resultados:

<?php

declare(strict_types=1);

$precios = [10.0, 25.5, 8.0];

$conIva = array_map(fn(float $p): float => round($p * 1.21, 2), $precios);
print_r($conIva);   // [12.1, 30.86, 9.68]

$nombres = ['ana', 'luis', 'marta'];
$capitalizados = array_map(ucfirst(...), $nombres);   // First-class callable
print_r($capitalizados);   // [Ana, Luis, Marta]

// Con varios arrays: recorre en paralelo
$productos = ['Café', 'Té'];
$cantidades = [2, 3];
$lineas = array_map(fn(string $p, int $c): string => "$c x $p", $productos, $cantidades);
print_r($lineas);   // [2 x Café, 3 x Té]

array_filter(): quedarse con algunos elementos

Devuelve solo los elementos para los que la función devuelve true. Conserva las claves:

<?php

declare(strict_types=1);

$notas = ['Ana' => 8.5, 'Luis' => 4.0, 'Marta' => 6.75, 'Pablo' => 3.5];

$aprobados = array_filter($notas, fn(float $nota): bool => $nota >= 5);
print_r($aprobados);   // [Ana => 8.5, Marta => 6.75]

// Filtrar por CLAVE
$config = ['db_host' => 'localhost', 'db_user' => 'root', 'app_name' => 'Tienda'];
$soloDb = array_filter(
    $config,
    fn(string $clave): bool => str_starts_with($clave, 'db_'),
    ARRAY_FILTER_USE_KEY
);
print_r($soloDb);   // [db_host => localhost, db_user => root]

// Filtrar por clave Y valor
$stock = ['manzanas' => 0, 'peras' => 12, 'plátanos' => 3];
$pocasUnidades = array_filter(
    $stock,
    fn(int $unidades, string $fruta): bool => $unidades > 0 && $unidades < 5,
    ARRAY_FILTER_USE_BOTH
);
print_r($pocasUnidades);   // [plátanos => 3]

// Sin función: elimina los valores "falsos" (0, '', null, false, [])
print_r(array_filter([1, 0, 'hola', '', null, 'adiós']));
// [0 => 1, 2 => hola, 5 => adiós]

⚠️ Importante: Como array_filter() conserva las claves, el resultado de filtrar una lista puede tener huecos ([0 => ..., 2 => ...]). Si necesitas una lista limpia (por ejemplo, para json_encode(), que de lo contrario generaría un objeto), envuelve el resultado en array_values().

array_reduce(): reducir a un único valor

Recorre el array acumulando un resultado. Recibe la función, que a su vez recibe el acumulador y el elemento actual, y el valor inicial:

<?php

declare(strict_types=1);

$carrito = [
    ['producto' => 'Libro', 'precio' => 18.0, 'cantidad' => 2],
    ['producto' => 'Agenda', 'precio' => 9.5, 'cantidad' => 1],
];

$total = array_reduce(
    $carrito,
    fn(float $acumulado, array $linea): float => $acumulado + $linea['precio'] * $linea['cantidad'],
    0.0
);

echo "Total: $total €" . PHP_EOL;   // Total: 45.5 €
Vuelta $acumulado $linea Resultado
1 0.0 Libro (18 × 2) 36.0
2 36.0 Agenda (9.5 × 1) 45.5

array_walk(): recorrer modificando en el sitio

array_walk() llama a la función con cada valor (por referencia, si quieres) y su clave. A diferencia de array_map(), modifica el array original y no devuelve uno nuevo:

<?php

declare(strict_types=1);

$precios = ['café' => 1.2, 'tostada' => 2.0];

array_walk($precios, function (float &$precio, string $producto): void {
    $precio = round($precio * 1.10, 2);   // Subida del 10 %
});

print_r($precios);   // [café => 1.32, tostada => 2.2]

8. Novedades de PHP 8.4 y 8.5

PHP 8.4: array_find(), array_find_key(), array_any() y array_all()

Antes había que escribir un foreach con break (o abusar de array_filter()) para tareas muy comunes. PHP 8.4 añadió cuatro funciones. Todas reciben el array y una función que recibe ($valor, $clave):

Función Devuelve
array_find($a, $fn) El primer valor que cumple la condición, o null
array_find_key($a, $fn) La clave del primer elemento que la cumple, o null
array_any($a, $fn) true si algún elemento la cumple
array_all($a, $fn) true si todos la cumplen
<?php

declare(strict_types=1);

$productos = [
    'P01' => ['nombre' => 'Silla', 'precio' => 49.0, 'stock' => 10],
    'P02' => ['nombre' => 'Mesa', 'precio' => 149.0, 'stock' => 0],
    'P03' => ['nombre' => 'Lámpara', 'precio' => 29.0, 'stock' => 4],
];

// Primer producto agotado
$agotado = array_find($productos, fn(array $p): bool => $p['stock'] === 0);
echo $agotado['nombre'] . PHP_EOL;   // Mesa

// Su código
$codigo = array_find_key($productos, fn(array $p): bool => $p['stock'] === 0);
echo $codigo . PHP_EOL;              // P02

// ¿Hay algún producto de más de 100 €?
var_dump(array_any($productos, fn(array $p): bool => $p['precio'] > 100));   // bool(true)

// ¿Todos tienen stock?
var_dump(array_all($productos, fn(array $p): bool => $p['stock'] > 0));      // bool(false)

// Si nada coincide, array_find devuelve null
var_dump(array_find($productos, fn(array $p): bool => $p['precio'] > 1000)); // NULL

⚠️ Importante: array_find() devuelve null tanto si no encuentra nada como si el valor encontrado es null. Si tu array puede contener null, usa array_find_key() y comprueba la clave con !== null.

PHP 8.5: array_first() y array_last()

Obtener el primer o el último valor de un array era sorprendentemente incómodo: reset() y end() mueven el puntero interno y no funcionan con expresiones, y $a[0] falla si las claves no empiezan en 0. PHP 8.5 lo resuelve:

<?php

declare(strict_types=1);

$clasificacion = ['Lola' => 98, 'Hugo' => 91, 'Noa' => 87];

echo array_first($clasificacion) . PHP_EOL;   // 98
echo array_last($clasificacion) . PHP_EOL;    // 87

// Combinadas con las de claves (PHP 7.3)
echo array_key_first($clasificacion) . PHP_EOL;   // Lola
echo array_key_last($clasificacion) . PHP_EOL;    // Noa

// Con un array vacío devuelven null
var_dump(array_first([]));   // NULL

// Funcionan con cualquier tipo de claves
$huecos = [5 => 'cinco', 2 => 'dos', 9 => 'nueve'];
echo array_first($huecos) . PHP_EOL;   // cinco  (el primero en orden, no la clave menor)
Antes de PHP 8.5 PHP 8.5
$a[array_key_first($a)] ?? null array_first($a)
$a[array_key_last($a)] ?? null array_last($a)
reset($a) (mueve el puntero, devuelve false si está vacío) array_first($a)
end($a) (mueve el puntero, devuelve false si está vacío) array_last($a)

9. Desestructuración

📘 Concepto: Desestructurar es extraer los elementos de un array a variables individuales en una sola instrucción. Es como vaciar una caja de herramientas colocando cada herramienta en su sitio.

Con arrays indexados

<?php

declare(strict_types=1);

$coordenadas = [40.4168, -3.7038];

[$latitud, $longitud] = $coordenadas;

echo "Lat: $latitud, Lon: $longitud" . PHP_EOL;   // Lat: 40.4168, Lon: -3.7038

// Saltar elementos
[, $segundo, , $cuarto] = ['a', 'b', 'c', 'd'];
echo $segundo . $cuarto . PHP_EOL;   // bd

// Intercambiar variables sin variable auxiliar
$a = 1;
$b = 2;
[$a, $b] = [$b, $a];
echo "$a $b" . PHP_EOL;   // 2 1

Con claves

<?php

declare(strict_types=1);

$usuario = ['id' => 42, 'nombre' => 'Olga', 'email' => 'olga@ejemplo.es', 'rol' => 'editor'];

['nombre' => $nombre, 'email' => $email] = $usuario;

echo "$nombre <$email>" . PHP_EOL;   // Olga <olga@ejemplo.es>

En un foreach

<?php

declare(strict_types=1);

$empleados = [
    ['nombre' => 'Sara', 'puesto' => 'Diseñadora'],
    ['nombre' => 'Iker', 'puesto' => 'Programador'],
];

foreach ($empleados as ['nombre' => $nombre, 'puesto' => $puesto]) {
    echo "$nombre - $puesto" . PHP_EOL;
}

list(): la forma antigua

Antes de PHP 7.1 se usaba list(). Funciona igual, pero la sintaxis [] es más moderna:

<?php

list($x, $y) = [10, 20];          // Antiguo
[$x, $y] = [10, 20];              // Moderno, equivalente

list('a' => $uno) = ['a' => 1];   // También admite claves

💡 Consejo: La desestructuración brilla con funciones que devuelven varios valores: [$cociente, $resto] = dividir(17, 5);. Lo aprovecharás en el módulo 07.


10. Arrays como pila y como cola

Pila (LIFO: el último en entrar es el primero en salir)

Como una pila de platos: pones encima y quitas de encima. Se usa para “deshacer”, historiales de navegación o analizar expresiones.

<?php

declare(strict_types=1);

$historial = [];

// Apilar (push)
$historial[] = 'Escribir "Hola"';
$historial[] = 'Poner en negrita';
$historial[] = 'Cambiar color';

// Desapilar (pop): deshacer la última acción
$deshecha = array_pop($historial);
echo "Deshecho: $deshecha" . PHP_EOL;            // Deshecho: Cambiar color
echo 'Última acción: ' . array_last($historial) . PHP_EOL;   // Poner en negrita

Cola (FIFO: el primero en entrar es el primero en salir)

Como la cola del supermercado. Se usa para procesar tareas en orden de llegada.

<?php

declare(strict_types=1);

$colaImpresion = ['factura.pdf', 'informe.docx'];

$colaImpresion[] = 'foto.jpg';   // Llega un trabajo nuevo al final

while (count($colaImpresion) > 0) {
    $trabajo = array_shift($colaImpresion);   // Atiende al primero
    echo "Imprimiendo $trabajo..." . PHP_EOL;
}
// Imprimiendo factura.pdf...
// Imprimiendo informe.docx...
// Imprimiendo foto.jpg...
Estructura Añadir Quitar Consultar sin quitar
Pila (LIFO) $a[] = $x / array_push() array_pop() array_last()
Cola (FIFO) $a[] = $x / array_push() array_shift() array_first()

💡 Consejo: array_shift() tiene que reindexar todo el array, así que con colas de miles de elementos es lento. Para esos casos PHP ofrece clases especializadas como SplQueue y SplStack.


11. Ejemplos completos

Ejemplo 1: Carrito de la compra

<?php

declare(strict_types=1);

const IVA = 0.21;
const ENVIO_GRATIS_DESDE = 50.0;
const GASTOS_ENVIO = 4.95;

$catalogo = [
    'LIB-01' => ['nombre' => 'El nombre del viento', 'precio' => 22.90],
    'LIB-02' => ['nombre' => 'Dune', 'precio' => 14.95],
    'CUA-01' => ['nombre' => 'Cuaderno A5', 'precio' => 3.50],
];

// El carrito guarda código => cantidad
$carrito = [];

// Añadir productos (si ya está, suma la cantidad)
$anadir = [['LIB-01', 1], ['CUA-01', 3], ['LIB-02', 1], ['CUA-01', 1]];
foreach ($anadir as [$codigo, $cantidad]) {
    $carrito[$codigo] = ($carrito[$codigo] ?? 0) + $cantidad;
}

// Eliminar un producto
unset($carrito['LIB-02']);

// Construir las líneas del ticket
$lineas = array_map(
    fn(string $codigo, int $cantidad): array => [
        'nombre' => $catalogo[$codigo]['nombre'],
        'cantidad' => $cantidad,
        'subtotal' => $catalogo[$codigo]['precio'] * $cantidad,
    ],
    array_keys($carrito),
    array_values($carrito)
);

$base = array_sum(array_column($lineas, 'subtotal'));
$iva = round($base * IVA, 2);
$envio = $base >= ENVIO_GRATIS_DESDE ? 0.0 : GASTOS_ENVIO;
$total = $base + $iva + $envio;

foreach ($lineas as ['nombre' => $nombre, 'cantidad' => $cantidad, 'subtotal' => $subtotal]) {
    printf("%-25s x%2d %8.2f €\n", $nombre, $cantidad, $subtotal);
}
echo str_repeat('-', 42) . PHP_EOL;
printf("%-29s %8.2f €\n", 'Base imponible', $base);
printf("%-29s %8.2f €\n", 'IVA (21 %)', $iva);
printf("%-29s %8.2f €\n", 'Transporte', $envio);
printf("%-29s %8.2f €\n", 'TOTAL', $total);

Salida:

El nombre del viento      x 1    22.90 €
Cuaderno A5               x 4    14.00 €
------------------------------------------
Base imponible                   36.90 €
IVA (21 %)                        7.75 €
Transporte                        4.95 €
TOTAL                            49.60 €

Ejemplo 2: Notas de alumnos

<?php

declare(strict_types=1);

$alumnos = [
    ['nombre' => 'Alba', 'notas' => [7.5, 8.0, 9.25]],
    ['nombre' => 'Bruno', 'notas' => [4.0, 5.5, 3.75]],
    ['nombre' => 'Carla', 'notas' => [9.0, 9.5, 10.0]],
    ['nombre' => 'Dani', 'notas' => [6.0, 4.5, 5.0]],
];

// 1. Calcular la media de cada alumno
$conMedia = array_map(
    fn(array $a): array => [
        ...$a,
        'media' => round(array_sum($a['notas']) / count($a['notas']), 2),
    ],
    $alumnos
);

// 2. Ordenar por media descendente
usort($conMedia, fn(array $a, array $b): int => $b['media'] <=> $a['media']);

// 3. Mostrar el ranking
foreach ($conMedia as $posicion => ['nombre' => $nombre, 'media' => $media]) {
    $estado = $media >= 5 ? 'Aprobado' : 'Suspenso';
    printf("%d. %-6s %5.2f  %s\n", $posicion + 1, $nombre, $media, $estado);
}

// 4. Estadísticas
$medias = array_column($conMedia, 'media');
$aprobados = array_filter($conMedia, fn(array $a): bool => $a['media'] >= 5);

echo PHP_EOL;
echo 'Media de la clase: ' . round(array_sum($medias) / count($medias), 2) . PHP_EOL;
echo 'Mejor alumno: ' . array_first($conMedia)['nombre'] . PHP_EOL;
echo 'Aprobados: ' . count($aprobados) . ' de ' . count($conMedia) . PHP_EOL;
echo '¿Alguna matrícula de honor (10)? '
    . (array_any($alumnos, fn(array $a): bool => in_array(10.0, $a['notas'], true)) ? 'Sí' : 'No')
    . PHP_EOL;

Salida:

1. Carla   9.50  Aprobado
2. Alba    8.25  Aprobado
3. Dani    5.17  Aprobado
4. Bruno   4.42  Suspenso

Media de la clase: 6.84
Mejor alumno: Carla
Aprobados: 3 de 4
¿Alguna matrícula de honor (10)? Sí

12. Ejercicios

Ejercicio 1: Agenda de contactos

Crea un array asociativo de 5 contactos donde la clave sea el nombre y el valor un array con telefono y email. Implementa: añadir un contacto, modificar el teléfono de uno, eliminar otro con unset(), comprobar si existe un nombre con array_key_exists() y mostrar todos ordenados alfabéticamente con ksort().

Ejercicio 2: Operaciones de conjuntos

Dados $a = [1, 2, 3, 4, 5] y $b = [4, 5, 6, 7], obtén la unión sin duplicados, la intersección y la diferencia ($a menos $b). Investiga en el manual las funciones array_intersect() y array_diff() y úsalas. Reindexa los resultados con array_values().

Ejercicio 3: Estadísticas de temperaturas

Dado un array con las temperaturas máximas de 14 días, calcula con funciones de arrays (sin bucles): la media, la máxima, la mínima, cuántos días superaron los 30 grados (array_filter + count), las temperaturas en Fahrenheit (array_map, F = C × 9/5 + 32) y si todos los días superaron los 15 grados (array_all).

Ejercicio 4: Inventario de una tienda

Con un array de productos (codigo, nombre, categoria, precio, stock):

  1. Obtén un array codigo => nombre con array_column().
  2. Agrupa los productos por categoría usando array_reduce() (resultado: ['Electrónica' => [...], 'Hogar' => [...]]).
  3. Calcula el valor total del inventario (precio × stock).
  4. Encuentra el primer producto sin stock con array_find().
  5. Ordena por categoría y, dentro de cada categoría, por precio descendente con un único usort().

Ejercicio 5: Palabras más frecuentes

Dado un texto largo, conviértelo en minúsculas, sepáralo en palabras con explode(' ', ...), elimina las vacías, cuenta cuántas veces aparece cada palabra (prueba la función array_count_values()), ordena de mayor a menor frecuencia con arsort() y muestra las 5 más repetidas con array_slice() (con el cuarto parámetro true para conservar las claves).


Resumen

Concepto Sintaxis / función
Crear $a = [1, 2];, $a = ['clave' => 'valor'];
Añadir al final $a[] = $valor;, array_push($a, $v1, $v2)
Quitar extremos array_pop(), array_shift(); añadir al inicio: array_unshift()
Eliminar unset($a['clave']) (no reindexa)
Contar / buscar count(), in_array($v, $a, true), array_search($v, $a, true)
Claves y valores array_keys(), array_values(), array_key_exists()
Unir array_merge(), [...$a, ...$b], $a + $b
Porciones array_slice() (copia), array_splice() (modifica)
Transformar estructura array_combine(), array_flip(), array_unique(), array_column()
Ordenar por valor sort(), rsort(), asort(), arsort()
Ordenar por clave ksort(), krsort()
Orden personalizado usort($a, fn($x, $y) => $x <=> $y)
Transformar array_map(fn($v) => ..., $a)
Filtrar array_filter($a, $fn, ARRAY_FILTER_USE_KEY)
Reducir array_reduce($a, $fn, $inicial)
Modificar en el sitio array_walk($a, function (&$v, $k) { ... })
PHP 8.4 array_find(), array_find_key(), array_any(), array_all()
PHP 8.5 array_first(), array_last()
Desestructurar [$a, $b] = $arr;, ['k' => $v] = $arr;
Pila / cola array_pop() / array_shift()