Mapping associative arrays in PHP
Trying to solve the same problem, I came across this Stack Overflow question about accessing keys in PHP’s array_map
. The accepted answer uses array_keys
, but this is unsatisfactory since it requires giving the array
a name (I wouldn’t have been Googling for a solution if it was so easy!).
Turns out there’s no great solution, so I added an answer listing a few alternatives. I’m shamelessly re-posting it here:
The Problem
When mapping an anonymous function
over an anonymous array
, there is no way to access the keys:
array_reduce
doesn’t get access to the keys either. array_walk
can access keys, but the array
is passed by reference, which we can’t do with anonymous values.
Solutions
Array of pairs
This is bad, since we’re changing the original array
, which might require pre-processing. Also, the boilerplate array()
calls increase linearly with the length of the array
`:
array_map(
function($pair) use ($foo) {
list($key, $val) = $pair;
/* ... */
},
array(array(key1, val1),
array(key2, val2),
/* ... */));
Temporary variable
We don’t need to pre-process the array
, and the boilerplate is constant, but we can accidentaly clobber an existing variable:
$i_hope_this_does_not_conflict = array(key1 => val1,
key2 => val2,
/* ... */);
array_map(
function($key, $val) use ($foo) { /* ... */ },
array_keys($i_hope_this_does_not_conflict),
$i_hope_this_does_not_conflict);
unset($i_hope_this_does_not_conflict);
One-shot function
We can use a function
to restrict the scope of our temporary variable and prevent clobbering existing names. One downside is that we need to add an extra use
clause for the values we’ll need:
call_user_func(
function($arr) use ($foo) {
return array_map(function($key, $val) use ($foo) { /* ... */ },
array_keys($arr),
$arr);
},
array(key1 => val1,
key2 => val2,
/* ... */));
Multi-argument one-shot function
We define the function
we’re mapping in the original scope to prevent the use
boilerplate:
call_user_func(
function($f, $arr) {
return array_map($f, array_keys($arr), $arr);
},
function($key, $val) use ($foo) { /* ... */ },
array(key1 => val1,
key2 => val2,
/* ... */));
New function
The interesting thing to note is that our last one-shot function
has a nice, generic signature and looks a lot like array_map
. We might want to give this a name so we can re-use it:
Our application code then gets back to where we started, but in the process we’ve gained a useful function
for our library: