Beim Verarbeiten von Arrays in PHP stellt sich regelmäßig die Frage nach dem passenden Werkzeug für wiederkehrende Aufgaben. Dieses Tutorial nimmt sich array_walk() vor, erklärt die Funktionsweise im Detail und zeigt, wann die Funktion gegenüber foreach und array_map die richtige Wahl ist.
Was macht PHP array_walk()?
Wer in PHP jedes Element eines Arrays mit derselben Logik bearbeiten will, etwa alle Werte trimmen, alle Preise mit Mehrwertsteuer multiplizieren oder alle Strings in Kleinbuchstaben umwandeln, hat zwei Standardwege: foreach oder array_map. Daneben steht eine dritte Funktion, die im Code häufig auftaucht und doch oft missverstanden wird: PHP array_walk. Die Funktion ruft einen Callback für jedes Element auf, hat dabei Zugriff auf Schlüssel und Werte und kann das Array direkt verändern.

Bevor die Referenz, der dritte $userdata-Parameter und das rekursive Pendant beleuchtet werden, lohnt der Blick auf den entscheidenden Unterschied zu array_map.
Der entscheidende Unterschied zu array_map() liegt in der In-Place-Modifikation. PHP array_walk() arbeitet auf dem Original-Array, sofern der Callback den Wert per Referenz übernimmt. Damit ist es das richtige Werkzeug, wenn das vorhandene Array umgebaut werden soll, ohne ein neues zu allokieren. Das Tutorial zeigt das Pattern Schritt für Schritt, klärt die Referenz, den dritten Parameter und das rekursive Pendant.
Syntax und die drei Parameter
Die Signatur ist auf den ersten Blick kompakt, hat aber mehrere subtile Punkte. PHP array_walk() erwartet das zu bearbeitende Array, einen Callback und optional einen dritten Wert, der dem Callback als Kontext mitgegeben wird.
<?php
array_walk(array|object &$array, callable $callback, mixed $arg = null): true
Der Callback hat seine eigene Signatur: function(mixed &$value, mixed $key, mixed $userdata = null). Wer den Wert per Referenz übernimmt (&$value), modifiziert direkt das Array. Wer ihn ohne Referenz nimmt, kann zwar lesen, aber nichts schreiben. Der Schlüssel ist immer nur lesbar. Der Rückgabewert von array_walk ist seit PHP 8.2 fest auf true, weil die Funktion nicht fehlschlagen kann.
Erstes Beispiel: alle Werte trimmen
Ein klassisches Szenario sind Werte aus einem Formular, die unter Umständen mit Leerzeichen verziert sind. PHP array_walk() bereinigt das Array in einer Zeile, ohne ein neues Array zu allokieren.
<?php
$werte = [' Anna ', ' Ben', 'Cara '];
array_walk($werte, function(string &$v): void {
$v = trim($v);
});
print_r($werte);
/* Array ( [0] => Anna [1] => Ben [2] => Cara ) */
Der Callback nimmt den Wert per Referenz, weist dem Element den getrimmten String zu, und das Original-Array enthält anschließend die bereinigten Werte. Das Pattern ist kompakter als eine foreach-Schleife mit eigener Index-Variable und macht die Absicht des Codes klar lesbar.
In-Place-Modifikation mit Referenz
Die Referenz ist der Kernunterschied zu array_map. Wer den Wert ohne & übernimmt, kann ihn nur lesen und nicht zurückschreiben. Das führt im Code-Review oft zu Verwirrung, weil das Array trotz array_walk-Aufruf unverändert bleibt.
<?php
$preise = [10, 20, 30];
/* OHNE Referenz: keine Wirkung */
array_walk($preise, function(int $p): void {
$p *= 2;
});
print_r($preise);
/* Array ( [0] => 10 [1] => 20 [2] => 30 ) */
/* MIT Referenz: in-place verdoppelt */
array_walk($preise, function(int &$p): void {
$p *= 2;
});
print_r($preise);
/* Array ( [0] => 20 [1] => 40 [2] => 60 ) */
Das & vor dem Parameter ist also nicht optional, sondern entscheidend. Wer das Pattern häufig braucht, kann den Callback auch als Closure mit Type-Hint schreiben oder eine benannte Funktion verwenden. In beiden Fällen muss die Referenz erhalten bleiben.
Der dritte Parameter $userdata
Der dritte Parameter ist eine elegante Möglichkeit, dem Callback einen externen Wert mitzugeben, ohne ihn über use ($var) einzufangen. Klassisches Beispiel ist ein MwSt-Faktor, der auf alle Preise angewendet werden soll.
<?php
$preise = [9.99, 19.99, 49.99];
$mwst = 1.19;
array_walk($preise, function(float &$p, $key, float $faktor): void {
$p = round($p * $faktor, 2);
}, $mwst);
print_r($preise);
/* Array ( [0] => 11.89 [1] => 23.79 [2] => 59.49 ) */
Der Callback bekommt drei Parameter: den Wert per Referenz, den Schlüssel und den $userdata-Wert. Das Pattern eignet sich besonders gut, wenn die Callback-Funktion in einer separaten Datei liegt und der Faktor erst zur Laufzeit feststeht. Mit Closures und use wäre dasselbe möglich, der explizite dritte Parameter macht den Code aber häufig lesbarer.
array_walk_recursive für verschachtelte Arrays
PHP array_walk() arbeitet nur auf der obersten Ebene des Arrays. Wer verschachtelte Strukturen bearbeiten will, etwa eine API-Antwort mit mehrdimensionalen Werten, nimmt das rekursive Pendant array_walk_recursive(). Die Funktion durchläuft das Array in die Tiefe und ruft den Callback nur für Blatt-Werte auf, nicht für Container.
<?php
$daten = [
'kunde' => [
'vorname' => ' Anna ',
'nachname' => ' Mueller ',
],
'adresse' => [
'strasse' => ' Hauptstr 1',
'ort' => ' Berlin ',
],
];
array_walk_recursive($daten, function(string &$v): void {
$v = trim($v);
});
print_r($daten);
/* alle Werte sind nun bereinigt, Struktur bleibt erhalten */
Das ist die schönste Lösung, wenn verschachtelte Daten einheitlich bearbeitet werden sollen. Wichtig zu wissen: Der Callback wird nicht für Sub-Arrays aufgerufen, nur für skalare Werte. Wer auch die Container-Struktur transformieren will, braucht eine eigene rekursive Funktion.
flowchart TD
A[Array uebergeben] --> B[Callback fuer Element]
B --> C{Mit Referenz?}
C -->|Ja| D[Wert in Array aktualisieren]
C -->|Nein| E[Wert bleibt unveraendert]
D --> F[Naechstes Element]
E --> F
F --> G{Letztes Element?}
G -->|Nein| B
G -->|Ja| H[true zurueckgeben]
Unterschied zu array_map und foreach
Die drei Funktionen array_walk, array_map und foreach überlappen in ihren Anwendungsbereichen, sind aber nicht austauschbar. Wer den Unterschied verstanden hat, trifft die richtige Wahl im Code-Review.
<?php
$werte = [1, 2, 3];
/* PHP array_walk modifiziert in-place, kein Rueckgabewert */
array_walk($werte, fn(int &$v) => $v *= 10);
/* $werte ist jetzt [10, 20, 30] */
/* array_map gibt ein neues Array zurueck, Original bleibt */
$werte = [1, 2, 3];
$neu = array_map(fn(int $v): int => $v * 10, $werte);
/* $werte = [1, 2, 3], $neu = [10, 20, 30] */
/* foreach ist die flexibelste Variante mit beliebigen Seiteneffekten */
foreach ($werte as &$v) {
$v *= 10;
}
unset($v);
Faustregel: PHP array_walk() ist die richtige Wahl, wenn das vorhandene Array umgebaut werden soll und kein neues Array gewollt ist. array_map() ist die richtige Wahl, wenn ein neues Array entstehen soll und das Original unverändert bleiben muss. foreach bleibt sinnvoll, wenn die Logik komplex ist oder mehrere Aktionen pro Iteration nötig sind.
Schlüssel: nur lesbar, nicht schreibbar
Eine wichtige Einschränkung ist die Behandlung der Schlüssel. Der Callback bekommt sie als zweiten Parameter, aber er kann sie nicht ändern. Wer die Schlüssel umbauen will, kommt mit array_walk nicht ans Ziel und muss stattdessen ein neues Array bauen, etwa mit array_combine oder einer foreach-Schleife.
<?php
$daten = ['name' => 'Anna', 'rolle' => 'admin'];
array_walk($daten, function(string &$v, string $k): void {
/* $k ist hier nur lesbar, kein &$k erlaubt */
$v = strtoupper($k) . ': ' . $v;
});
print_r($daten);
/* Array ( [name] => NAME: Anna [rolle] => ROLLE: admin ) */
Wer die Schlüssel im Wert mitführen will, ist mit diesem Pattern gut bedient. Wer die Schlüssel komplett ersetzen will, braucht einen anderen Ansatz. In den meisten Anwendungsfällen reicht aber das Bearbeiten der Werte vollkommen aus.
Objekte iterieren mit array_walk
Ein wenig bekanntes Detail: Die Signatur von array_walk akzeptiert nicht nur ein Array, sondern auch ein Objekt (array|object &$array). Das Verhalten ist die Iteration über alle öffentlich sichtbaren Properties des Objekts, ähnlich wie bei foreach ($objekt as $key => $value). Das ist praktisch für Datenobjekte und DTOs, die schnell normalisiert werden sollen.
<?php
class Profil {
public string $name = ' Anna ';
public string $stadt = ' Berlin ';
public string $rolle = ' admin ';
}
$p = new Profil();
array_walk($p, function(string &$v): void {
$v = trim($v);
});
print_r($p);
/* Profil Object ( [name] => Anna [stadt] => Berlin [rolle] => admin ) */
Wichtig: Nur Public-Properties sind erreichbar, geschachtelte Properties oder Properties mit __get/__set-Magie werden nicht berücksichtigt. Für komplexere Objekt-Strukturen ist Reflection oder ein expliziter foreach-Loop über die Properties die robustere Wahl. Für DTOs mit reinen Public-Properties ist array_walk aber die kompakteste Variante.
Performance und Best Practices
PHP array_walk() ist intern in C implementiert, der Callback dagegen wird im PHP-Userland ausgeführt. Das macht die Funktion insgesamt langsamer als ein einfacher foreach mit Inline-Code, weil pro Iteration der Funktionsaufruf-Overhead anfällt. Bei wenigen tausend Elementen ist der Unterschied vernachlässigbar, bei Millionen Elementen wird foreach spürbar schneller.
Drei Best Practices haben sich bewährt. Erstens, das & vor dem Wert-Parameter ist Pflicht, sobald das Array verändert werden soll. Wer es vergisst, schreibt einen No-Op. Zweitens, bei verschachtelten Arrays nicht selbst rekursiv durchlaufen, sondern array_walk_recursive() nutzen. Drittens, im Code-Review prüfen, ob array_walk wirklich gebraucht wird oder ob array_map (kein Side-Effect, neues Array) klarer wäre.
Ein typischer Bug ist die Annahme, dass array_walk ein neues Array zurückgibt. Der Rückgabewert ist seit PHP 8.2 immer true, das eigentliche Ergebnis liegt im übergebenen Array. Wer aus alter Gewohnheit $neu = array_walk(...) schreibt, hat anschließend $neu = true und ein modifiziertes Original-Array.
Fazit
PHP array_walk() ist eine kompakte Funktion, die einen Callback auf jedes Element eines Arrays anwendet und es bei Bedarf in-place modifiziert. Sie ist das richtige Werkzeug für alle Fälle, in denen das vorhandene Array umgebaut werden soll und die Speicher-Allokation eines zweiten Arrays vermieden werden kann. Wer die Referenz korrekt nutzt, den dritten $userdata-Parameter elegant einsetzt und array_walk klar von array_map abgrenzt, trifft im Code-Review jedes Mal die richtige Wahl zwischen den drei Schleifen-Varianten.