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 entfernt 0, '0', false und [] 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, ...).