0

array_walk, array_walk_recursive — mutating in place

Intermediate5 min read·php-04-011

Concept

array_walk($array, $callback, $extra) applies a user function to every element of an array in-place, modifying the original array rather than returning a new one. The callback receives the element value and key as parameters; with &$value in the signature, you can mutate the value directly. The $extra parameter passes an additional value to every callback invocation without needing a closure to capture it.

array_walk_recursive($array, $callback) does the same but descends into nested arrays, visiting every leaf value regardless of nesting depth. It does NOT call the callback on intermediate array nodes — only on scalar leaf values.

array_walk vs array_map: array_map returns a new array (functional style, no mutation); array_walk mutates the original and returns true/false. For readability and immutability, prefer array_map — it communicates intent better. Use array_walk when you need the key in your transformation (array_map doesn't pass keys) or when you explicitly want in-place mutation of a large array to avoid an extra allocation.

When array_walk is genuinely useful: sanitizing user input arrays, applying a format transformation where keys matter, initializing or resetting values with context-dependent logic.

Code Example

php
<?php
declare(strict_types=1);

// Basic array_walk — multiply each value by a factor
$prices = ['apple' => 1.50, 'banana' => 0.75, 'cherry' => 3.00];
array_walk($prices, function(float &$price, string $key, float $tax): void {
    $price = round($price * (1 + $tax), 2);
}, 0.20); // 20% tax passed as $extra

print_r($prices);
// ['apple' => 1.80, 'banana' => 0.90, 'cherry' => 3.60]

// array_walk with key usage (array_map can't easily do this)
$slugs = [];
$titles = ['php-intro' => 'PHP Introduction', 'oop-basics' => 'OOP Basics'];
array_walk($titles, function(string $title, string $slug) use (&$slugs): void {
    $slugs[$slug] = strtolower(str_replace(' ', '-', $title));
});

// array_walk_recursive — traverse nested arrays
$config = [
    'db' => ['host' => '  localhost  ', 'name' => '  myapp  '],
    'cache' => ['driver' => '  redis  '],
    'app' => 'My App  ',
];
array_walk_recursive($config, function(mixed &$value): void {
    if (is_string($value)) {
        $value = trim($value);
    }
});
print_r($config);
// All string values are trimmed, structure preserved

// Comparison: array_map (no mutation, no key access)
$nums = [1, 2, 3, 4, 5];
$doubled = array_map(fn($n) => $n * 2, $nums);
// $nums unchanged, $doubled is new array

// array_walk equivalent (mutates $nums)
array_walk($nums, function(int &$n): void { $n *= 2; });
// $nums is now [2, 4, 6, 8, 10]

Interview Q&A

Q: What is the difference between array_walk and array_map, and when would you choose one over the other?

array_map is functional — it returns a new array and leaves the input unchanged, making data flow explicit. array_walk mutates the input array in-place and returns a boolean. Choose array_map by default for clarity and immutability. Use array_walk when you need access to the array key in your transformation (the callback signature is callback($value, $key)) — array_map doesn't provide keys. Also prefer array_walk when you explicitly need in-place mutation for memory efficiency on very large arrays.


Q: What does array_walk_recursive do differently from a recursive custom function?

array_walk_recursive only calls your callback on scalar leaf values — it silently skips intermediate arrays and descends into them automatically. A custom recursive function gives you full control: you can call your logic on both intermediate arrays and leaf values, handle objects, and control the recursion depth. array_walk_recursive is appropriate for flat transformations of all leaf values (trim whitespace, cast to string); a custom function is needed when the transformation is structure-aware.