Aikido

Warum Sie array_filter() in PHP mit array_values() umwickeln sollten

Fehlerrisiko

Regel
Array-Filterergebnisse mit array_values() umschließen
Funktionen wie array_filter() behalten die ursprünglichen Schlüssel bei,
was zu Fehlern führen kann, wenn der Code sequentielle
numerische Indizes ab 0 erwartet.

Unterstützte Sprachen: PHP

Einleitung

PHPs array_filter() bewahrt die ursprünglichen Array-Schlüssel beim Filtern von Elementen, selbst bei numerisch indizierten Arrays. Nach dem Filtern [0 => 'a', 1 => 'b', 2 => 'c'] um Index 1 zu entfernen, erhalten Sie [0 => 'a', 2 => 'c'] mit einer Lücke in den numerischen Schlüsseln. Code, der sequentielle Indizes ab 0 erwartet, bricht beim Zugriff ab $array[1] oder iterieren mit Annahmen über fortlaufende Indizes. Dieses Verhalten überrascht Entwickelnde, die aus anderen Sprachen kommen, in denen das Filtern neu indizierte Arrays zurückgibt.

Warum es wichtig ist

Code-Wartbarkeit: Nicht-sequentielle Array-Schlüssel erzeugen subtile Fehler, die nur unter bestimmten Bedingungen auftreten. Code, der mit ungefilterten Arrays einwandfrei funktioniert, schlägt nach dem Filtern mysteriöserweise fehl, wenn er davon ausgeht count($array) - 1 ist der höchste gültige Index. Das Debuggen dieser Probleme verschwendet Zeit, da die Grundursache nicht offensichtlich ist: Sie sehen ein Array mit drei Elementen, können aber nicht auf das zweite mit Index 1 zugreifen.

JSON-Kodierungsprobleme: Wenn Sie json_encode() ein Array mit nicht-sequenziellen Schlüsseln, behandelt PHP es als Objekt statt als Array, was zu folgendem Ergebnis führt: {"0":"a","2":"c"} anstatt ["a","c"]. Frontend-Code, der JSON-Arrays erwartet, erhält stattdessen Objekte, wodurch Iteration und Array-Methoden fehlschlagen. Diese Diskrepanz zwischen PHP-Arrays und JavaScript-Arrays verursacht Integrationsfehler, die erst nach Filteroperationen auftreten.

Iterations- und Paginierungsfehler: Code, der Ergebnisse paginiert oder Arrays in Blöcke aufteilt, bricht, wenn Schlüssel nicht sequenziell sind. Schleifen von 0 bis count($array) greift auf undefinierte Indizes zu. Verwendung von array_slice() für die Paginierung führt zu unerwarteten Ergebnissen, da sie auf Positionen operiert, aber ursprüngliche Schlüssel zurückgibt. Diese Fehler häufen sich in komplexen Datenverarbeitungspipelines.

Code-Beispiele

❌ Nicht konform:

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

Warum es falsch ist: Nachdem das Filtern den Index 0 entfernt hat, hat das Array die Schlüssel [1, 2] anstatt [0, 1], wodurch $activeUsers[0] undefined. Die JSON-Kodierung erzeugt ein Objekt anstelle eines Arrays, da die Schlüssel nicht sequenziell sind, was Frontend-Code, der Arrays erwartet, beschädigt.

✅ Konform:

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

Warum dies wichtig ist: array_values() indiziert das gefilterte Array neu, um sequenzielle numerische Schlüssel ab 0 zu erhalten, was den Indexzugriff vorhersehbar macht und sicherstellt, dass die JSON-Kodierung Arrays anstelle von Objekten erzeugt. Die Funktion verhält sich wie erwartet, unabhängig davon, welche Elemente herausgefiltert wurden.

Fazit

Immer umhüllen array_filter(), array_diff(), und ähnliche Funktionen mit array_values() wenn Sie sequentielle numerische Indizes benötigen. Dies verhindert subtile Fehler durch nicht-sequentielle Schlüssel und stellt sicher, dass die JSON-Kodierung Arrays anstelle von Objekten erzeugt. Die Leistungskosten sind im Vergleich zur eingesparten Debugging-Zeit vernachlässigbar.

FAQs

Haben Sie Fragen?

Welche PHP-Array-Funktionen behalten Schlüssel bei und benötigen array_values()?

array_filter(), array_diff(), array_diff_key(), array_intersect() und array_intersect_key() behalten alle die ursprünglichen Schlüssel bei. Funktionen wie array_map() mit einem einzelnen Array-Parameter behalten ebenfalls die Schlüssel bei. Jede Funktion, die als schlüsselerhaltend dokumentiert ist, sollte mit array_values() umschlossen werden, wenn Sie sequentielle Indizes benötigen.

Hat array_values() Auswirkungen auf die Performance?

Minimal. `array_values()` iteriert einmal durch das Array, um es neu zu indizieren, was O(n) ist, aber in der Praxis sehr schnell. Diese Kosten sind im Vergleich zur Filteroperation selbst vernachlässigbar und weit geringer als das Debuggen von Produktionsproblemen, die durch nicht-sequentielle Schlüssel entstehen. Priorisieren Sie immer die Korrektheit vor vorzeitiger Optimierung.

Was ist mit assoziativen Arrays mit String-Schlüsseln?

Verwenden Sie array_values() nicht bei assoziativen Arrays, deren Schlüssel aussagekräftige Strings sind. Dies würde Ihre String-Schlüssel durch numerische Indizes ersetzen und wichtige Informationen verlieren. Diese Regel gilt nur für numerisch indizierte Arrays, bei denen sequentielle Schlüssel ab 0 erwartet werden.

Kann ich stattdessen array_splice() oder andere Funktionen verwenden?

array_splice() indiziert automatisch neu, ist aber für das Einfügen/Entfernen gedacht, nicht für das Filtern. Für Filteroperationen ist array_filter() mit array_values() klarer und idiomatischer. Verwenden Sie das richtige Werkzeug für die Aufgabe, anstatt Funktionen zu missbrauchen, um eine Neuindizierung als Nebeneffekt zu erzielen.

Wie teste ich auf dieses Problem in meiner Codebasis?

Suchen Sie nach `array_filter()`-Aufrufen, deren Ergebnisse über numerische Indizes abgerufen, in JSON kodiert oder an Funktionen übergeben werden, die sequentielle Schlüssel erwarten. Testen Sie mit Daten, bei denen gefilterte Elemente nicht am Ende des Arrays stehen. Wenn das Entfernen der ersten oder mittleren Elemente Fehler verursacht, benötigen Sie `array_values()`.

Werden Sie jetzt sicher.

Sichern Sie Ihren Code, Ihre Cloud und Ihre Laufzeit in einem zentralen System.
Finden und beheben Sie Schwachstellen schnell und automatisch.

Keine Kreditkarte erforderlich | Scan-Ergebnisse in 32 Sek.