PHP: Wie prüft man ob ein Array eine Liste oder assoziativ ist?
PHP kennt nur einen Array-Typ, der sowohl als Liste als auch als Wörterbuch dient. Manchmal muss man aber wissen welches von beidem gerade vorliegt — und spätestens bei JSON wird es wichtig.
Ab PHP Version 8.1
Seit PHP 8.1 gibt es dafür eine eingebaute Funktion:
array_is_list().
Sie liefert true, wenn die Schlüssel bei 0 beginnen, ganzzahlig sind und
lückenlos aufsteigen:
['a','b','c'] => true
[0=>'a', 1=>'b'] => true
[1=>'a', 2=>'b'] => false (beginnt nicht bei 0)
[0=>'a', 2=>'b'] => false (Lücke)
['x'=>1] => false
[] => true (das leere Array gilt als Liste)
Der letzte Fall ist bewusst so gewählt: Ein leeres Array kann man ohne Widerspruch als leere Liste auffassen.
Vor PHP Version 8.1
Setzt du eine ältere Version ein, findest du überall diese Faustformel:
<?php
function istListe(array $a): bool {
return array_keys($a) === range(0, count($a) - 1);
}
?>
Die funktioniert — bis auf einen Fall. Vergleichen wir sie mit der eingebauten Funktion:
alte Formel array_is_list
['a','b'] true true
[] false true <- Abweichung
[1=>'a'] false false
['0'=>'a'] true true
Beim leeren Array liefert die alte Formel false, hält es also für
assoziativ. Der Grund steckt in range():
range(0, -1) => [0, -1]
Ist der Startwert größer als der Endwert, zählt range() rückwärts. Bei einem
leeren Array wird also [] mit [0, -1] verglichen, und das ist erwartungsgemäß
nicht dasselbe.
Wenn du diese Formel noch irgendwo im Code stehen hast, lohnt es sich gezielt danach zu suchen. Falls du bei PHP 8.0 oder älter bleiben musst, hilft eine zusätzliche Abfrage:
<?php
function istListe(array $a): bool {
if ($a === []) {
return true;
}
return array_keys($a) === range(0, count($a) - 1);
}
?>
Numerische Schlüssel als String
Ein Detail, das oft für Verwirrung sorgt: PHP wandelt numerische String-Schlüssel automatisch in Integer um.
['0'=>'x','1'=>'y'] keys : [0,1]
Typ des ersten Schlüssels : int
['0' => 'a'] verhält sich also nicht nur wie eine Liste, es ist eine.
Diese Umwandlung passiert immer, nicht nur beim Vergleich.
Warum das überhaupt wichtig ist
Die Unterscheidung wirkt akademisch, bis man sie einmal an einer Schnittstelle
übersehen hat. json_encode() erzeugt nämlich unterschiedliche Formate:
json_encode(['a','b','c']) => ["a","b","c"]
Ein Array. Jetzt entfernen wir ein Element:
<?php
$liste = ['a', 'b', 'c'];
unset($liste[1]);
echo json_encode($liste);
?>
{"0":"a","2":"c"}
Aus dem Array ist ein Objekt geworden. Und das muss auch so sein, denn ein JSON-Array hat keine Schlüssel, mit denen sich die Lücke abbilden ließe.
Für den Client deiner Schnittstelle ist das aber ein Formatwechsel. Wer ein Array erwartet und plötzlich ein Objekt bekommt, bricht ab — und zwar nur manchmal, nämlich genau dann wenn ein Element entfernt wurde. Solche Fehler sucht man lange.
Die Lösung ist ein array_values() bevor die Daten das Haus verlassen:
json_encode(array_values($liste)) => ["a","c"]
Zusammenfassung
- Ab PHP 8.1:
array_is_list(). - Die alte Formel mit
range()beantwortet das leere Array falsch. - Numerische String-Schlüssel werden automatisch zu Integern.
- Vor
json_encode()einarray_values(), wenn das Ergebnis ein JSON-Array sein soll.
Hinweis zu Netcup (Werbung)
Der deutsche Hoster Netcup bietet unter anderem günstige und zugleich leistungsstarke Webhosting Pakete, KVM-basierte Root Server und dezidierte Server an. Mit unseren Gutscheincodes kannst du noch mehr Geld sparen (6€ bei deiner ersten Bestellung, 30% Rabatt auf alle KVM-basierten Root Server, ...).