Here is a patch that refactors drupal_map_assoc() removing foreach loops by making use of PHP5's array_combine() function and array_map().
| Comment | File | Size | Author |
|---|---|---|---|
| #7 | drupal.drupal-map-assoc.7.patch | 940 bytes | sun |
| drupal_map_assoc.patch | 925 bytes | recidive |
Comments
Comment #1
recidive commentedHere is a small test:
And the results:
Is it worth writing tests for such simple function?
Comment #2
catchYes. Yes it is.
http://coverage.cwgordon.com ;)
Comment #3
recidive commentedInteresting. While working on tests for drupal_map_assoc() I discovered a bug on the current implementation. Not sure if it's a PHP limitation but:
and
return
While
returns
As you can see, PHP just ignores the decimal part on examples 1 and 2. The same occurs with the current implementation of drupal_map_assoc(). But not with the implementation on my patch, except when passing a function on the second argument (array_map() also strips out the decimal part). This is bad because someone could be using drupal_map_assoc() on a select field of some module setting and want the actual float value to be variable_set()'ed.
Ideas anyone?
Comment #4
c960657 commentedIt is a limitation in PHP. Only strings and integers are allowed as keys (see the manual page about arrays). In your last example, the key is the string "1.5" (you can see that if you use var_dump() rather than print_r()). Apparently array_combine() casts the keys to strings.
I cannot replicate that. Could you supply a testcase?
You might want to replace this with
if (is_callable($function)) {. This will allow $function to be a class method specified using the array syntax, e.g.array('MyClass', 'myMethod')orarray($object, 'myMethod').Comment #5
Garrett Albright commentedI am running into a bug (?) like this in Drupal 6. I'm coding a site which searches a database of real estate properties, and want people to be able to select the number of bathrooms. "Half-bathrooms" are counted as .5 a bathroom, so a house with two bathrooms and one half-bathroom has 2.5 bathrooms. Unfortunately, I must use PHP 4; "pirets_range()" below is a workaround for PHP 4's inability to use the "$step" parameter of the standard range() function.
I thought about hacking drupal_map_assoc() in various ways -- strvaling all keys, all the time, or maybe just strvaling the keys if it looks like any of the parameters are not ints -- though that would require pre-looping through the array for possibly the entire length of it… Not increasing the execution time by up to 2x would be a good idea, I think. Eventually I decided to try converting the values to strings before passing them to drupal_map_assoc(). But that exposes another curious behavior!
So I've got the right number of elements this time, but the keys are cycling back and forth between ints and strings! Aah, the joy of duck-typed languages.
In my case this is acceptable behavior, though, and I presume it will be in most others' cases as well.
Comment #6
c960657 commentedThis is also a (somewhat surprising) PHP limitation/feature. If a key is a string containing an integer it is converted to that integer, i.e. string(1) "3" is converted to int(3).
Though this behaviour may appear a bit weird, I have managed to program PHP for years without even noticing it, so I guess it wont matter to most people. At least there is nothing that Drupal can do about it.
Comment #7
sunLooks reasonable.
Incorporated c279364's feedback from #4.
Comment #8
sun#367711: Shorten drupal_map_assoc() approached almost the same, and contains some additional concerns:
- Handling of empty arrays.
- Usage of array_walk() instead of array_map().
Comment #10
recidive commentedComment #12
moshe weitzman commentedSigh. I rewrote this yet another time and just found this patch. Hope someone can track down these test exceptions.
Comment #13
moshe weitzman commentedLooking at the new drupal_map_assoc, I'm thinking that it can just go away. Just about every caller can just do array_combine($array, $array) and get on with life.
Comment #15
sunWhy is it still green then?
Comment #16
moshe weitzman commentedAh, indeed it is. RTBC then.
Comment #17
sunerr? :-D
Comment #18
dries commentedCommitted to CVS HEAD.