Aikido

Por que você deve envolver array_filter() com array_values() em PHP

Risco de Bug

Regra
Envolver matriz filtragem resultados com array_values()
Funções como array_filter() preservam chaves chaves,
que podem causar erros quando o código espera sequencial
índices índices a partir a partir 0.

Idiomas suportados: PHP

Introdução

Do PHP array_filter() preserva as chaves originais do array ao filtrar elementos, mesmo para arrays indexados numericamente. Após a filtragem [0 => 'a', 1 => 'b', 2 => 'c'] para remover o índice 1, você obtém [0 => 'a', 2 => 'c'] com uma lacuna nas chaves numéricas. O código que espera índices sequenciais a partir de 0 falha ao acessar $array[1] ou iterando com suposições sobre índices contínuos. Esse comportamento surpreende desenvolvedores vindos de outras linguagens onde a filtragem retorna arrays reindexados.

Por que isso importa

Manutenibilidade do código: Chaves de array não sequenciais criam bugs sutis que só aparecem em condições específicas. O código que funciona bem com arrays não filtrados falha misteriosamente após a filtragem quando assume count($array) - 1 é o índice válido mais alto. Depurar esses problemas desperdiça tempo porque a causa raiz não é óbvia; você vê um array com três elementos, mas não consegue acessar o segundo com o índice 1.

Problemas de codificação JSON: Quando você json_encode() um array com chaves não sequenciais, o PHP o trata como um objeto em vez de um array, produzindo {"0":"a","2":"c"} em vez de ["a","c"]. O código frontend que espera arrays JSON recebe objetos em vez disso, quebrando a iteração e os métodos de array. Essa incompatibilidade entre arrays PHP e arrays JavaScript causa bugs de integração que só aparecem após operações de filtragem.

Erros de iteração e paginação: Código que pagina resultados ou divide arrays em blocos falha quando as chaves não são sequenciais. Looping de 0 a count($array) acessa índices indefinidos. Usando array_slice() para paginação produz resultados inesperados porque opera em posições, mas retorna chaves originais. Esses bugs se acumulam em pipelines complexos de processamento de dados.

Exemplos de código

❌ Não-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 que está errado: Após a filtragem remover o índice 0, o array possui as chaves [1, 2] em vez de [0, 1], tornando $activeUsers[0] indefinido. A codificação JSON produz um objeto em vez de um array porque as chaves não são sequenciais, quebrando o código frontend que espera arrays.

✅ Compatível:

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 que isso importa: array_values() reindexa o array filtrado para chaves numéricas sequenciais começando de 0, tornando o acesso ao índice previsível e garantindo que a codificação JSON produza arrays em vez de objetos. A função se comporta como esperado, independentemente de quais elementos foram filtrados.

Conclusão

Sempre envolva array_filter(), array_diff(), e funções similares com array_values() quando você precisa de índices numéricos sequenciais. Isso evita bugs sutis de chaves não sequenciais e garante que a codificação JSON produza arrays em vez de objetos. O custo de desempenho é insignificante em comparação com o tempo de depuração economizado.

FAQs

Dúvidas?

Quais funções de array PHP preservam as chaves e precisam de array_values()?

array_filter(), array_diff(), array_diff_key(), array_intersect() e array_intersect_key() preservam todas as chaves originais. Funções como array_map() com um único parâmetro de array também preservam as chaves. Qualquer função documentada como preservadora de chaves deve ser envolvida por array_values() se você precisar de índices sequenciais.

array_values() tem implicações de desempenho?

Mínimo. `array_values()` itera pelo array uma vez para reindexá-lo, o que é O(n), mas muito rápido na prática. Esse custo é desprezível em comparação com a própria operação de filtragem e muito menor do que depurar problemas de produção decorrentes de chaves não sequenciais. Sempre priorize a correção em vez da otimização prematura.

E quanto aos arrays associativos com chaves de string?

Não use array_values() em arrays associativos onde as chaves são strings significativas. Isso substituiria suas chaves de string por índices numéricos, perdendo informações importantes. Esta regra se aplica apenas a arrays indexados numericamente onde chaves sequenciais a partir de 0 são esperadas.

Posso usar array_splice() ou outras funções em vez disso?

array_splice() reindexa automaticamente, mas é destinado à inserção/remoção, não à filtragem. Para operações de filtragem, array_filter() com array_values() é mais claro e idiomático. Use a ferramenta certa para a tarefa, em vez de abusar de funções para obter reindexação como efeito colateral.

Como testar este problema na minha base de código?

Procure por chamadas `array_filter()` cujos resultados são acessados por índice numérico, codificados para JSON, ou passados para funções que esperam chaves sequenciais. Teste com dados onde os elementos filtrados não estão no final do array. Se a remoção dos primeiros ou elementos do meio causar bugs, você precisa de `array_values()`.

Fique seguro agora

Proteja seu código, Cloud e runtime em um único sistema centralizado.
Encontre e corrija vulnerabilidades rapidamente de forma automática.

Não é necessário cartão de crédito | Resultados da varredura em 32 segundos.