Aikido

Perché in PHP è consigliabile racchiudere array_filter() all’interno di array_values()

Rischio di bug

Regola
Wrap array filtraggio risultati con array_values()
Funzioni come array_filter() mantengono le chiavi,
il quale possono causare errori quando il codice si aspetta valori
numerici indici a partire da 0.

Lingue supportate: PHP

Introduzione

PHP array_filter() mantiene le chiavi originali dell'array durante il filtraggio degli elementi, anche nel caso di array indicizzati numericamente. Dopo il filtraggio [0 => 'a', 1 => 'b', 2 => 'c'] per rimuovere l'indice 1, si ottiene [0 => 'a', 2 => 'c'] con una lacuna nei tasti numerici. Il codice che si aspetta indici sequenziali a partire da 0 non funziona correttamente quando si accede a $array[1] oppure eseguendo iterazioni basate su ipotesi relative agli 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 degli array non sequenziali generano bug impercettibili che si manifestano solo in determinate condizioni. Il codice che funziona correttamente con array non filtrati fallisce misteriosamente dopo il filtraggio quando 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 tu json_encode() un array con chiavi non sequenziali; PHP lo tratta come un oggetto anziché come un array, generando {"0":"a","2":"c"} anziché ["a", "c"]. Il codice frontend, che si aspetta array JSON, riceve invece oggetti, compromettendo il funzionamento dei metodi di iterazione e degli array. Questa discrepanza tra gli array PHP e quelli JavaScript causa bug di integrazione che si manifestano solo dopo le operazioni di filtraggio.

Errori di iterazione e impaginazione: Il codice che impagina i risultati o suddivide gli array in blocchi smette di funzionare quando le chiavi non sono sequenziali. Eseguendo un ciclo da 0 a count($array) acceda a indici non definiti. Utilizzando array_slice() La paginazione produce risultati inaspettati perché opera sulle posizioni ma restituisce le chiavi originali. Questi bug si aggravano nelle pipeline complesse di elaborazione dei dati.

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é è sbagliato: Dopo che il filtro ha rimosso l'indice 0, l'array contiene le chiavi [1, 2] anziché [0, 1], rendendo $activeUsers[0] undefined. La codifica JSON genera un oggetto anziché un array poiché le chiavi non sono sequenziali, causando il malfunzionamento del codice frontend che si aspetta 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é è importante: array_values() reindicizza l'array filtrato in chiavi numeriche sequenziali a partire da 0, rendendo prevedibile l'accesso tramite indice e garantendo che la codifica JSON produca array anziché oggetti. La funzione si comporta come previsto indipendentemente dagli elementi che sono stati filtrati.

Conclusione

Avvolgere sempre array_filter(), array_diff(), e funzioni simili con array_values() quando sono necessari indici numerici sequenziali. Ciò evita bug difficili da individuare causati da chiavi non sequenziali e garantisce che la codifica JSON produca array anziché oggetti. Il costo in termini di prestazioni è trascurabile rispetto al tempo risparmiato nel debug.

Domande frequenti

Hai delle domande?

Quali funzioni PHP relative agli array mantengono le chiavi e richiedono l'uso di `array_values()`?

Le funzioni array_filter(), array_diff(), array_diff_key(), array_intersect() e array_intersect_key() mantengono tutte le chiavi originali. Anche funzioni come array_map(), quando hanno un unico parametro di tipo array, mantengono le chiavi. Qualsiasi funzione documentata come tale da mantenere le chiavi dovrebbe essere racchiusa in array_values() se sono necessari indici sequenziali.

La funzione array_values() ha ripercussioni sulle prestazioni?

Minimo. La funzione `array_values()` esegue una sola iterazione sull'array per reindicizzarlo; si tratta di un'operazione di complessità O(n), ma in pratica molto veloce. Questo costo è trascurabile rispetto all'operazione di filtraggio stessa ed è di gran lunga inferiore rispetto al tempo necessario per risolvere i problemi di produzione causati da chiavi non sequenziali. È sempre meglio privilegiare la correttezza rispetto a un'ottimizzazione prematura.

E gli array associativi con chiavi di tipo stringa?

Non utilizzare la funzione `array_values()` su array associativi in cui le chiavi sono stringhe significative. La funzione sostituirebbe le chiavi stringa con indici numerici, causando la perdita di informazioni importanti. Questa regola si applica solo agli array indicizzati numericamente in cui ci si aspetta che le chiavi siano sequenziali a partire da 0.

Posso usare invece array_splice() o altre funzioni?

array_splice() provvede automaticamente alla reindicizzazione, ma è pensata per l'inserimento e la rimozione, non per il filtraggio. Per le operazioni di filtraggio, array_filter() insieme ad array_values() è più chiara e più idiomatica. È meglio usare lo strumento giusto per il lavoro da svolgere, piuttosto che abusare delle funzioni per ottenere la reindicizzazione come effetto collaterale.

Come posso verificare la presenza di questo problema nel mio codice?

Cerca le chiamate a `array_filter()` i cui risultati vengono accessibili tramite indice numerico, convertiti in JSON o passati a funzioni che richiedono chiavi sequenziali. Esegui dei 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 errori, devi utilizzare `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.