Aikido

Pourquoi envelopper array_filter() avec array_values() en PHP

Risque de bug

Règle
Envelopper tableau filtrage résultats avec array_values()
Fonctions telles que array_filter() préservent clés ,
qui peuvent provoquer des bugs lorsqu'ils code s'attend séquentiel
numériques séquentiels commençant à 0.

Langues prises en charge : PHP

Introduction

De PHP array_filter() préserve les clés de tableau d'origine lors du filtrage des éléments, même pour les tableaux indexés numériquement. Après le filtrage [0 => 'a', 1 => 'b', 2 => 'c'] pour supprimer l'index 1, vous obtenez [0 => 'a', 2 => 'c'] avec un écart dans les clés numériques. Le code qui s'attend à des index séquentiels à partir de 0 se bloque lors de l'accès $array[1] ou itérer en faisant des suppositions sur des index continus. Ce comportement surprend les développeurs venant d'autres langages où le filtrage renvoie des tableaux réindexés.

Pourquoi c'est important

Maintenabilité du code : Les clés de tableau non séquentielles créent des bugs subtils qui n'apparaissent que dans des conditions spécifiques. Le code qui fonctionne correctement avec des tableaux non filtrés échoue mystérieusement après le filtrage lorsqu'il suppose count($array) - 1 est l'indice valide le plus élevé. Le débogage de ces problèmes fait perdre du temps car la cause première n'est pas évidente : vous voyez un tableau de trois éléments mais ne pouvez pas accéder au deuxième avec l'indice 1.

Problèmes d'encodage JSON : Lorsque vous json_encode() un tableau avec des clés non séquentielles, PHP le traite comme un objet au lieu d'un tableau, produisant {"0":"a","2":"c"} au lieu de ["a","c"]. Le code frontend s'attendant à des tableaux JSON reçoit des objets à la place, ce qui interrompt l'itération et les méthodes de tableau. Cette incompatibilité entre les tableaux PHP et JavaScript provoque des bugs d'intégration qui n'apparaissent qu'après les opérations de filtrage.

Erreurs d'itération et de pagination : Le code qui pagine les résultats ou divise les tableaux en blocs se rompt lorsque les clés ne sont pas séquentielles. Boucler de 0 à count($array) accède à des index indéfinis. Utilisation array_slice() pour la pagination produit des résultats inattendus car elle opère sur des positions mais renvoie les clés originales. Ces bugs s'aggravent dans les pipelines de traitement de données complexes.

Exemples de code

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

Pourquoi c'est incorrect : Après que le filtrage a supprimé l'index 0, le tableau a les clés [1, 2] au lieu de [0, 1], rendant $activeUsers[0] Non défini. L'encodage JSON produit un objet au lieu d'un tableau car les clés ne sont pas séquentielles, ce qui rompt le code frontend qui s'attend à des tableaux.

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

Pourquoi c'est important : array_values() réindexe le tableau filtré avec des clés numériques séquentielles à partir de 0, rendant l'accès aux index prévisible et garantissant que l'encodage JSON produit des tableaux au lieu d'objets. La fonction se comporte comme prévu, quels que soient les éléments filtrés.

Conclusion

Toujours encapsuler array_filter(), array_diff(), et des fonctions similaires avec array_values() lorsque vous avez besoin d'index numériques séquentiels. Cela évite les bugs subtils liés aux clés non séquentielles et garantit que l'encodage JSON produit des tableaux au lieu d'objets. Le coût de performance est négligeable comparé au temps de débogage économisé.

FAQ

Des questions ?

Quelles fonctions de tableau PHP conservent les clés et nécessitent array_values() ?

array_filter(), array_diff(), array_diff_key(), array_intersect() et array_intersect_key() préservent toutes les clés d'origine. Les fonctions comme array_map() avec un seul paramètre de tableau préservent également les clés. Toute fonction documentée comme préservant les clés doit être enveloppée avec array_values() si vous avez besoin d'index séquentiels.

array_values() a-t-il des implications sur les performances ?

Minimal. array_values() parcourt le tableau une seule fois pour le réindexer, ce qui est en O(n) mais très rapide en pratique. Ce coût est négligeable comparé à l'opération de filtrage elle-même et bien moins que le débogage de problèmes de production dus à des clés non séquentielles. Priorisez toujours la correction par rapport à l'optimisation prématurée.

Qu'en est-il des tableaux associatifs avec des clés de type chaîne de caractères ?

N'utilisez pas array_values() sur des tableaux associatifs dont les clés sont des chaînes de caractères significatives. Cela remplacerait vos clés de chaîne par des index numériques, entraînant une perte d'informations importantes. Cette règle s'applique uniquement aux tableaux indexés numériquement où des clés séquentielles commençant à 0 sont attendues.

Puis-je utiliser array_splice() ou d'autres fonctions à la place ?

array_splice() réindexe automatiquement, mais elle est conçue pour l'insertion/suppression, pas pour le filtrage. Pour les opérations de filtrage, array_filter() avec array_values() est plus clair et plus idiomatique. Utilisez le bon outil pour la tâche plutôt que d'abuser des fonctions pour obtenir une réindexation comme effet secondaire.

Comment tester cette problématique dans ma base de code ?

Recherchez les appels à `array_filter()` dont les résultats sont accédés par index numérique, encodés en JSON ou passés à des fonctions attendant des clés séquentielles. Testez avec des données où les éléments filtrés ne sont pas à la fin du tableau. Si la suppression des premiers ou des éléments du milieu provoque des bugs, vous avez besoin de `array_values()`.

Sécurisez-vous maintenant.

Sécuriser votre code, votre cloud et votre runtime dans un système centralisé unique.
Détectez et corrigez les vulnérabilités rapidement et automatiquement.

Pas de carte de crédit requise | Résultats du scan en 32 secondes.