Aikido

Por qué deberías encapsular array_filter() con array_values() en PHP

Riesgo de bug

Regla
Envolver los resultados del filtrado de arrays con array_values()
Funciones como array_filter() conservan las claves originales,
lo que puede causar errores cuando el código espera índices
numéricos secuenciales a partir de 0.

Lenguajes compatibles: PHP

Introducción

De PHP array_filter() conserva las claves originales del array al filtrar elementos, incluso para arrays indexados numéricamente. Después de filtrar [0 => 'a', 1 => 'b', 2 => 'c'] para eliminar el índice 1, se obtiene [0 => 'a', 2 => 'c'] con un hueco en las claves numéricas. El código que espera índices secuenciales a partir de 0 falla al acceder $array[1] o iterando con suposiciones sobre índices continuos. Este comportamiento sorprende a los desarrolladores que provienen de otros lenguajes donde el filtrado devuelve arrays reindexados.

Por qué es importante

Mantenibilidad del código: Las claves de array no secuenciales crean errores sutiles que solo aparecen en condiciones específicas. El código que funciona bien con arrays sin filtrar falla misteriosamente después de filtrar cuando asume recuento($array) - 1 es el índice válido más alto. Depurar estos problemas hace perder tiempo porque la causa raíz no es obvia: ves un array con tres elementos pero no puedes acceder al segundo con el índice 1.

Problemas de codificación JSON: Cuando json_encode() un array con claves no secuenciales, PHP lo trata como un objeto en lugar de un array, produciendo {"0":"a","2":"c"} en lugar de ["a","c"]. El código frontend que espera arrays JSON recibe objetos en su lugar, rompiendo la iteración y los métodos de array. Esta inconsistencia entre los arrays de PHP y los arrays de JavaScript causa errores de integración que solo aparecen después de las operaciones de filtrado.

Errores de iteración y paginación: El código que pagina resultados o divide arrays en fragmentos falla cuando las claves no son secuenciales. Iterar de 0 a recuento($array) accede a índices indefinidos. Utilizando array_slice() para la paginación produce resultados inesperados porque opera sobre posiciones pero devuelve claves originales. Estos errores se agravan en pipelines complejos de procesamiento de datos.

Ejemplos de código

❌ No conforme:

function getActiveUsers(array $users): array {
    $activeUsers = array_filter($users, function($user) {
        return $user['status'] === 'active';
    });

    // Bug: assumes index 0 exists and keys are sequential
    $firstActive = $activeUsers[0] ?? null;

    // Bug: JSON encodes as object if keys aren't sequential
    return json_encode($activeUsers);
}

$users = [
    ['id' => 1, 'status' => 'inactive'],
    ['id' => 2, 'status' => 'active'],
    ['id' => 3, 'status' => 'active']
];

// Returns {"1":{"id":2...},"2":{"id":3...}} (object, not array)
getActiveUsers($users);

Por qué es incorrecto: Después de que el filtrado elimina el índice 0, el array tiene las claves [1, 2] en lugar de [0, 1], haciendo $activeUsers[0] No definido. La codificación JSON produce un objeto en lugar de un array porque las claves no son secuenciales, rompiendo el código frontend que espera arrays.

✅ Conforme:

function getActiveUsers(array $users): string {
    $activeUsers = array_filter($users, function($user) {
        return $user['status'] === 'active';
    });

    // Reindex to sequential keys starting from 0
    $activeUsers = array_values($activeUsers);

    // Now index 0 always exists for non-empty arrays
    $firstActive = $activeUsers[0] ?? null;

    // JSON encodes as proper array: [{"id":2...},{"id":3...}]
    return json_encode($activeUsers);
}

$users = [
    ['id' => 1, 'status' => 'inactive'],
    ['id' => 2, 'status' => 'active'],
    ['id' => 3, 'status' => 'active']
];

// Returns [{"id":2...},{"id":3...}] (array, as expected)
getActiveUsers($users);

¿Por qué esto importa? array_values() reindexa el array filtrado a claves numéricas secuenciales que comienzan desde 0, haciendo que el acceso al índice sea predecible y asegurando que la codificación JSON produzca arrays en lugar de objetos. La función se comporta como se espera, independientemente de los elementos que se hayan filtrado.

Conclusión

Envuelva siempre array_filter(), array_diff(), y funciones similares con array_values() cuando necesite índices numéricos secuenciales. Esto previene errores sutiles causados por claves no secuenciales y asegura que la codificación JSON produzca arrays en lugar de objetos. El coste de rendimiento es insignificante en comparación con el tiempo de depuración ahorrado.

Preguntas frecuentes

¿Tiene preguntas?

¿Qué funciones de array de PHP conservan las claves y necesitan array_values()?

array_filter(), array_diff(), array_diff_key(), array_intersect() y array_intersect_key() todas preservan las claves originales. Funciones como array_map() con un único parámetro de array también preservan las claves. Cualquier función documentada como preservadora de claves debería ser envuelta con array_values() si necesita índices secuenciales.

¿`array_values()` tiene implicaciones en el rendimiento?

Mínimo. `array_values()` itera a través del array una vez para reindexarlo, lo cual es O(n) pero muy rápido en la práctica. Este coste es insignificante comparado con la propia operación de filtrado y mucho menor que depurar problemas de producción derivados de claves no secuenciales. Priorice siempre la corrección sobre la optimización prematura.

¿Qué pasa con los arrays asociativos con claves de cadena?

No uses array_values() en arrays asociativos donde las claves son cadenas significativas. Reemplazaría tus claves de cadena por índices numéricos, perdiendo información importante. Esta regla se aplica solo a arrays indexados numéricamente donde se esperan claves secuenciales que comienzan desde 0.

¿Puedo usar array_splice() o otras funciones en su lugar?

array_splice() reindexa automáticamente, pero está pensada para inserción/eliminación, no para filtrado. Para operaciones de filtrado, array_filter() con array_values() es más claro y más idiomático. Utilice la herramienta adecuada para la tarea en lugar de abusar de las funciones para obtener la reindexación como efecto secundario.

¿Cómo pruebo este problema en mi base de código?

Busque llamadas a array_filter() cuyos resultados se acceden por índice numérico, se codifican a JSON o se pasan a funciones que esperan claves secuenciales. Pruebe con datos donde los elementos filtrados no estén al final del array. Si la eliminación de los primeros o intermedios elementos causa errores, necesita array_values().

Asegúrate ahora.

Proteja su código, la nube y el entorno de ejecución en un único sistema central.
Encuentre y corrija vulnerabilidades de forma rápida y automática.

No se requiere tarjeta de crédito | Resultados del escaneo en 32 segundos.