Aikido

Perché dovresti racchiudere array_filter() con array_values() in PHP

Rischio di bug

Regola
Racchiudi i risultati del filtraggio dell'array con array_values()
Funzioni come array_filter() mantengono le chiavi originali,
il che può causare bug quando il codice si aspetta indici numerici
sequenziali che partono da 0. 

Linguaggi supportati: PHP

Introduzione

La funzione di PHP array_filter() mantiene le chiavi originali dell'array durante il filtraggio degli elementi, anche per gli array indicizzati numericamente. Dopo il filtraggio [0 => 'a', 1 => 'b', 2 => 'c'] per rimuovere l'indice 1, si ottiene [0 => 'a', 2 => 'c'] con un'interruzione nelle chiavi numeriche. Il codice che si aspetta indici sequenziali a partire da 0 si interrompe durante l'accesso $array[1] o quando si esegue un'iterazione basata sull'assunzione di indici continui. Questo comportamento sorprende gli sviluppatori provenienti da altri linguaggi in cui il filtraggio restituisce array reindicizzati.

Perché è importante

Manutenibilità del codice: Le chiavi di array non sequenziali generano bug subdoli che si manifestano solo in condizioni specifiche. Il codice che funziona correttamente con array non filtrati fallisce misteriosamente dopo il filtraggio se presuppone che count($array) - 1 è l'indice valido più alto. Risolvere questi problemi comporta una perdita di tempo perché la causa principale non è evidente: si vede un array con tre elementi, ma non è possibile accedere al secondo con l'indice 1.

Problemi di codifica JSON: Quando json_encode() un array con chiavi non sequenziali, PHP lo tratta come un oggetto anziché come un array, producendo {"0":"a","2":"c"} anziché ["a","c"]. Il codice di frontend che si aspetta array JSON riceve invece oggetti, compromettendo l'iterazione e i metodi degli array. Questa discrepanza tra array PHP e array JavaScript causa bug di integrazione che si manifestano solo dopo le operazioni di filtraggio.

Errori di iterazione e paginazione: Il codice che分页 (pagineggia) i risultati o suddivide gli array in blocchi si interrompe quando le chiavi non sono sequenziali. L'esecuzione di un ciclo da 0 a count($array) accede a indici non definiti. L'utilizzo di array_slice() per la paginazione produce risultati imprevisti perché opera sulle posizioni ma restituisce le chiavi originali. Questi bug si aggravano nelle pipeline di elaborazione dati complesse.

Esempi di codice

❌ Non 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);

Perché è errato: Dopo che il filtraggio ha rimosso l'indice 0, l'array ha le chiavi [1, 2] anziché [0, 1], rendendo $activeUsers[0] non definito. La codifica JSON produce un oggetto anziché un array perché le chiavi non sono sequenziali, compromettendo il codice di frontend che si aspetta degli array.

✅ 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);

Perché questo è importante: array_values() reindicizza l'array filtrato in chiavi numeriche sequenziali a partire da 0, rendendo prevedibile l'accesso agli indici e garantendo che la codifica JSON produca array anziché oggetti. La funzione si comporta come previsto indipendentemente dagli elementi filtrati.

Conclusione

Includi sempre array_filter(), array_diff(), e funzioni simili con array_values() quando hai bisogno di indici numerici sequenziali. Questo previene bug difficili da individuare dovuti a chiavi non sequenziali e assicura che la codifica JSON produca array anziché oggetti. Il costo in termini di prestazioni è trascurabile rispetto al tempo di debug risparmiato.

FAQ

Hai domande?

Quali funzioni per array PHP mantengono le chiavi e richiedono array_values()?

array_filter(), array_diff(), array_diff_key(), array_intersect() e array_intersect_key() mantengono tutte le chiavi originali. Funzioni come array_map() con un singolo parametro array preservano anch'esse le chiavi. Qualsiasi funzione documentata come conservativa delle chiavi dovrebbe essere racchiusa in array_values() se hai bisogno di indici sequenziali.

array_values() ha risvolti sulle prestazioni?

Minimi. array_values() scorre l'array una sola volta per indicizzarlo nuovamente, il che richiede un tempo O(n) ma è molto rapido nella pratica. Questo costo è trascurabile rispetto all'operazione di filtraggio stessa e di gran lunga inferiore al debug di problemi in produzione derivanti da chiavi non sequenziali. Dai sempre priorità alla correttezza rispetto all'ottimizzazione prematura.

Che dire degli array associativi con chiavi stringa?

Non usare array_values() su array associativi in cui le chiavi sono stringhe significative. Sostituirebbe le chiavi stringa con indici numerici, perdendo informazioni importanti. Questa regola si applica solo agli array indicizzati numericamente in cui ci si attende chiavi sequenziali a partire da 0.

‍

Posso usare array_splice() o altre funzioni in alternativa?

array_splice() reindicizza automaticamente, ma è pensato per inserimenti/rimozioni, non per il filtraggio. Per le operazioni di filtraggio, array_filter() con array_values() è più chiaro e idiomatico. Usa lo strumento giusto per il lavoro invece di abusare delle funzioni per ottenere la reindicizzazione come effetto collaterale.

‍

Come posso testare questo problema nella mia codebase?

Cerca chiamate a array_filter() i cui risultati vengono accessibili tramite indice numerico, codificati in JSON o passati a funzioni che si aspettano chiavi sequenziali. Esegui test con dati in cui gli elementi filtrati non si trovano alla fine dell'array. Se la rimozione del primo elemento o di quelli centrali causa bug, hai bisogno di array_values().

‍

Metti in sicurezza ora

Metti in sicurezza il tuo codice, il cloud e il runtime in un unico sistema centralizzato.
Trova e risolvi le vulnerabilità rapidamente e automaticamente.

Nessuna carta di credito richiesta | Risultati della scansione in 32 secondi.