I'm proposing a new function similar to the implementation of array_map
that allows us to apply a user-supplied callback to every element in the
array with the addition of the callback being passed the key as well as the
value of each element. Additionally, I would like to propose that the
callback can modify both the key as well as the value by return an array
where the key would be used to replace the existing key and the value would
replace the existing value.

Currently, getting the key into the callback is only possible with
array_map by passing in a second array. Modifying both values (or applying
the return value of the callback to both the key and the value) is not
possible with array_map. Modifying the existing behavior of the function
would cause BC breaks since there are probably a lot of people using code
similar to the following:

array_map('strlen', array('foo','bar','baz','quix'));

Where strlen expects exactly one parameter and handing two arguments would
cause it to implicitly return null and issue an E_WARNING with each
iteration of array_map.

To get both the key and the value into the callback you would have to do
something like the following:

array_map('my_callback', $array, array_keys($array));

Unfortunately, this has some performance and memory implications. PHP
arrays carry a lot of overhead and a large enough array means we hand a
copy of they array keys as an array to the function. This may be
unnecessary with a slightly improved implementation.

So instead we would have to have a new function like array_map_key
(perhaps) that passes two arguments to the callback on each iteration (the
key and the value of each element).

This would make the following code possible...


function my_call_back($key, $value) {
    return array($value, strlen($value));
}
$array = str_word_count("PHP is lots of fun!");
$array = array_map_key('my_call_back', $array);


The result would be the following array:

array(5) {
  ["PHP"]=>
  int(3)
  ["is"]=>
  int(2)
  ["lots"]=>
  int(4)
  ["of"]=>
  int(2)
  ["fun"]=>
  int(3)
}


This demonstrates modifying both the key as well as the value by applying a
user supplied callback function to each of the array's elements.

This can also be done with the foreach construct, but the problem with
foreach constructs is that they are not reusable. Since array_map takes a
callback it's easy to reuse the callback function in various places to
modify similar data structures. This is not so with foreach. It can be
argued that we simply put the foreach loop into a function and reuse that,
but there is a slight performance optimization with the implementation of
array_map that foreach can't do and that's that array_map can iterate over
all of the arrays supplied at once and more quickly than user space can do
the iteration.

It wouldn't be too hard to modify the implementation of array_map (
http://lxr.php.net/xref/PHP_5_5/ext/standard/array.c#4270) to pass in the
key and be able to return a new array where both key/value pairs are
applied by the callback given the existing implementation already accesses
this information with each iteration (so there's no noticeable performance
degradation). The only change would be in constructing the new return value
to include the key from the return value instead of using the existing key.

I would like to get everyone's thoughts on introducing such a function into
PHP 5.NEXT (obviously I'm too late for 5.5). If there is a real need for
this function out there and I'm not the only one that thinks this is useful
I would be happy to draft an RFC and provide an implementation.


Regards,
Sherif
I don't just make coffee around the office. Sometimes they let me write
code!

Reply via email to