PHP: Wie entfernt man leere Elemente aus einem Array?
array_filter($array) ist die Antwort, die man überall findet. Sie ist kurz,
sie funktioniert — und sie entfernt mehr, als die meisten erwarten. Unter
anderem die Zahl Null.
Die kurze Antwort
<?php
$sauber = array_values(array_filter($array, fn($v) => $v !== ''));
?>
Etwas länger als das übliche array_filter($array), dafür macht sie genau
das, was dasteht. Warum die Unterschiede wichtig sind, zeige ich jetzt.
Was array_filter() ohne Callback wirklich tut
Ohne Callback behält array_filter() alle Elemente, die truthy sind. Das
ist etwas anderes als “nicht leer”:
<?php
$roh = ['a', '', 'b', null, 'c', 0, '0', false, [], 'd', ' '];
$gefiltert = array_filter($roh);
?>
vorher : ["a","","b",null,"c",0,"0",false,[],"d"," "]
nachher : {"0":"a","2":"b","4":"c","9":"d","10":" "}
Die vollständige Liste:
0 entfernt '0.0' bleibt
'0' entfernt ' ' bleibt
0.0 entfernt 'a' bleibt
'' entfernt
null entfernt
false entfernt
[] entfernt
Die beiden Zeilen, die man sich merken sollte, stehen nebeneinander: Ein
String mit drei Leerzeichen bleibt, der String '0' fliegt raus.
Bei Formulardaten ist das fast immer genau verkehrt herum. Werte aus $_POST
sind ausnahmslos Strings, und '0' ist eine völlig normale Eingabe — eine
Stückzahl, ein Rabatt, eine Hausnummer. Die geht dir hier verloren. Der Nutzer
hat etwas eingegeben, dein Code tut so, als hätte er das Feld leer gelassen.
Was du stattdessen schreibst
Sag explizit, was “leer” für dich bedeutet:
<?php
// nur echte Leerstrings
$a = array_filter($werte, fn($v) => $v !== '');
// nur null
$b = array_filter($werte, fn($v) => $v !== null);
// beides
$c = array_filter($werte, fn($v) => $v !== '' && $v !== null);
?>
Wenn Leerzeichen mitgehen sollen, was bei Eingabefeldern meistens der Fall ist:
ohne trim : ["a"," ","\t","\n","b"]
mit trim : ["a","b"]
<?php
$d = array_filter($werte, fn($v) => trim($v) !== '');
?>
Man findet in den Antworten auch array_filter($array, 'strlen'). Das
funktioniert, meldet aber seit PHP 8.1 eine Deprecation, sobald ein null im
Array steht:
Deprecated: strlen(): Passing null to parameter #1 ($string)
of type string is deprecated
Das Ergebnis stimmt, der Hinweis landet trotzdem im Log. Und in PHP 9 wird
daraus ein TypeError. Der eigene kleine Callback ist es wert.
Die Lücken in den Schlüsseln sind kein Schönheitsproblem
array_filter() erhält die Schlüssel. Danach ist dein Array also keine Liste
mehr:
keys nach array_filter : [0,2]
Das sieht harmlos aus, bis du das Array als JSON herausgibst:
json_encode : {"0":"a","2":"b"} <- Objekt, nicht Array!
nach array_values() : ["a","b"]
Aus einem JSON-Array wird ein JSON-Objekt. Jeder Client, der ein Array erwartet — JavaScript, eine App, eine andere API — bricht daran. Und der Fehler tritt nur auf, wenn tatsächlich etwas gefiltert wurde, also typischerweise nicht in deinen Tests.
Deshalb: array_values() außenrum, wann immer das Ergebnis eine Liste sein
soll. Bei einem assoziativen Array natürlich nicht — da zerstört es dir die
Schlüssel.
array_filter() ist nicht rekursiv
Bei verschachtelten Arrays wird nur die oberste Ebene angefasst:
einfach : {"a":1,"b":{"c":null,"d":2}}
rekursiv : {"a":1,"b":{"d":2}}
Das null in der inneren Ebene überlebt. Eine rekursive Variante ist schnell
geschrieben:
<?php
function saeubern(array $a): array {
foreach ($a as $s => $x) {
if (is_array($x)) {
$a[$s] = saeubern($x);
} elseif ($x === null) {
unset($a[$s]);
}
}
return $a;
}
?>
Nach Schlüsseln filtern
Der dritte Parameter wird selten erwähnt, ist aber praktisch:
<?php
// interne Felder aussortieren
$oeffentlich = array_filter($daten,
fn($s) => !str_starts_with($s, '_'), ARRAY_FILTER_USE_KEY);
// Wert und Schlüssel zugleich
$beides = array_filter($daten,
fn($v, $s) => $v !== '' && !str_starts_with($s, '_'),
ARRAY_FILTER_USE_BOTH);
?>
USE_KEY : {"name":"x","ort":""}
USE_BOTH : {"name":"x"}
Achte auf die Reihenfolge bei USE_BOTH: erst der Wert, dann der
Schlüssel. Das ist genau umgekehrt zu dem, was man von foreach gewohnt ist.
Wo das leere Element meistens herkommt
Zum Schluss die eigentliche Ursache. In den allermeisten Fällen entsteht das
leere Element bei einem explode():
explode(',', '') : [""] <- ein Element, nicht null
count davon : 1
explode(',', 'a,,b') : ["a","","b"]
danach array_filter : ["a","b"]
Die erste Zeile ist der Klassiker. explode() auf einem leeren String liefert
nicht ein leeres Array, sondern ein Array mit einem leeren String darin.
count() davon ist 1. Wer also prüft, ob der Nutzer etwas eingegeben hat,
indem er die Elemente zählt, bekommt immer mindestens eins.
Wenn du die Eingabe vorher prüfst, brauchst du das Filtern oft gar nicht:
<?php
$teile = $eingabe === '' ? [] : explode(',', $eingabe);
?>
Zusammenfassung
array_filter()ohne Callback entfernt0,'0',falseund[]mit.- Bei Formulardaten ist das fast immer falsch, weil
'0'eine gültige Eingabe ist. - Schreib den Callback hin:
fn($v) => $v !== ''. - Leerzeichen mitnehmen:
trim($v) !== ''. array_values()außenrum, sonst wird aus dem JSON-Array ein JSON-Objekt.array_filter()ist nicht rekursiv.explode(',', '')liefert['']und nicht[]— meist die eigentliche Ursache.
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, ...).