Introducing array_column() in PHP 5.5
Earlier today, David Soria Parra declared a feature freeze on PHP 5.5 and tagged php-5.5.0beta1, but not before merging in pull request #257, which includes my humble addition to the PHP programming language: array_column().
The story of array_column() begins at PHP Tek in 2008. As I recall, it was Spooons who suggested it to me. It is functionality that nearly every developer has to implement in user-land code at some point in their careers, so I felt it only natural that it be built into the language, so I did just that.
My original patch for array_column() was written for PHP 5.2, but it sat around collecting dust for many years, until April of last year, when PHP moved to git and GitHub. That’s when it became easy enough to apply the patch and send a pull request, which I did. It wasn’t quite that simple, though, since I had to follow the official PHP project RFC process, but it wasn’t a pain either.
My goal for array_column() was simplicity. Many implement the functionality in different ways, and many call the function by other names (such as “pluck”), but I wanted to keep it simple and recognizable. It follows this function signature:
array array_column(array $input, mixed $columnKey[, mixed $indexKey])
Given a multi-dimensional array of data, array_column() returns the values from a single column of the input array, identified by the $columnKey. Optionally, you may provide an $indexKey to index the values in the returned array by the values from the $indexKey column in the input array.
For example, using the following array of data, we tell array_column() to return an array of just the last names, indexed by their record IDs.
$records = array(
array(
'id' => 2135,
'first_name' => 'John',
'last_name' => 'Doe'
),
array(
'id' => 3245,
'first_name' => 'Sally',
'last_name' => 'Smith'
),
array(
'id' => 5342,
'first_name' => 'Jane',
'last_name' => 'Jones'
),
array(
'id' => 5623,
'first_name' => 'Peter',
'last_name' => 'Doe'
)
);
$lastNames = array_column($records, 'last_name', 'id');
If we call print_r() on $lastNames, you’ll see a resulting array that looks a bit like this:
Array
(
[2135] => Doe
[3245] => Smith
[5342] => Jones
[5623] => Doe
)
And that’s all there is to it. I hope you find my little addition to the PHP language helpful. I had a lot of fun writing it, and following the PHP RFC process was a great learning experience.
41 Comments
I will definetly go though my code and replace some old helper functions as soon as we upgrade to 5.5, thank you for your work!
Nice...Would be great if this function would check whether the value is "callable" and if so, call it and use the returned value.
Love the functionality. Looking forward to the day when I can update my public libraries to 5.5 to take advantage of this. I can see vast improvements in code simplicity and efficiency, but sadly I still need to get the userbase off 5.2 first :(
Cool! That's a nice addition...
Great deal. Been wanting this for awhile now :)
Great news. I missed this function.
Nice addition... it's great that it made it's way to PHP 5.5 after all these years
Must say I still don't get it, why this must be yet-another-core-array*-function instead of userland-code. You know: You can write functions too :) It would look the same, behave the same and so on. But in the meantime I stooped trying to understand the core-devs decisions ^^
A useful library function is often one that would often otherwise be implemented in user-land code. But by compiling it into the core of the language, you can get a many times faster implementation, and users can focus on the core logic that they need to write, rather than utilities.
I cant imagine, that something like this would lead to an incredible performance boost. And usually a project/component/library already has a set of utility functions/methods, especially because this is a no-brainer http://pastebin.com/RriJ3KNj
Look at how this works with Ruby. The gems can be either C or Ruby (I think). There should be a similar thing for PHP I think. It would keep the PHP core light and provide an easy way to extend it.
That would be awesome! I can imagine something like this in combination with this PR https://github.com/composer... for composer. It would be really great if we could have project related extensions.
Thanks for your reply :-)
Good to see the Composer guys are thinking about this. Having to get extensions from all these different places is kind of a pain.
pecl is kinda doing the job, and you can load extensions dynamicly using ini_set as far as I know.
All these ini settings have to be the worst "feature" of PHP, IMO. Sorry but I don't see that as a good solution.
Also, the problem is that PECL is separate from Composer. This means you have to start managing dependencies from different places, which is a pain. If you could install these C extensions via Composer with auto compilation, that would be nice!
built in function will ALWAYS be faster, than our scripted thing. This function is a something I've been using extensively over the past few years, though I called it array_reindex(input, new_index, optional_values/columns)
congrats, great work!
Nice-looking function! Thanks for adding it.
Finally. This function covers one of the most use-cases that's always annoying to do with foreach :)
If you are looking for more such functions plus the ability to provide callbacks have a look at https://github.com/lstrojny...
Ben, this is a really great addition and thanks for taking the time to put it in. This is something that I know, personally, will come in very handy. I should pluck up the courage to do this myself (after brushing up my C/C++ skills).
Support for Windows XP and 2003 has been dropped.
That's really poor!
Windows > XP is crap
Great! Always nice to see when something useful like this goes into core.
Such a simple addition. Now that I thought of it more suprised it isnt already there. Great work,
may be array_column is the same as array_fill_keys and 2 array_map?
well, since i'm using array_map(function (array $arr) use ($name) { return $arr[$name]; }, $target); all the time, it will be nice to have simple replacement )
I'm excited to see this become a fast core function!
But I don't understand why if the column is not present in all rows, the returned array is shorter than the passed in array. Doesn't that make this dangerous to use with array_multisort, one of its stated goals?
My naive userland implementation throws a bad index warning, but the returned array still has an entry with value null.
(Strangely, can't find a _contact_ (not comment) form here.)
Ben, could you clarify whether you have plans to make second parameter of array_column() function optional to make it possible to have entire rows (not just a column) as values of each element (indexed by a specified-column's values) in array returned by the function (as proposed in bug-report #64493)?
The bug-report #64493 at PHP's bug tracker appears as assigned to you, but I'm not sure whether you assigned it to you yourself or someone made this (somewhat automatically) just because you are the author of the feature while you maybe even don't know about this proposal bug.
As said in the bug report, it's important to roll out the proposed subfeature in the _same_ PHP version as the function itself — otherwise it will be difficult for pure-script polyfills to determine what version of the native function is supported by specific PHP version.
Thanks.
Link for the lazy: https://bugs.php.net/bug.ph...
Hi,
I couldn't find a version of this function in plain PHP which is neither broken, incomplete nor handles null values correctly. So I wrote my own unit-tested version, which you find here: http://pastie.org/7277198
Thanks, Fabian.
I haven't blogged about it yet, but if you're interested, I've also provided a user-land version with Composer support here: https://github.com/ramsey/a...
You can also find it on Packagist.
Another reason I'm looking forward to PHP 5.5. Can't tell you how many times I could have used this.
One nice thing about having it built-in is that it runs faster than a userland function.
Array_column in PHP 5.5. Great stuffs from you. I searching about the same one and got it from here and cleared all my doubt. Thanks mate.
Nice addition to the core, this will come in very handy. I've had to write helper functions to do this in the past :)
array (
0 => 10,
1 => 20,
2 => 21,
3 => 22,
)
NULL values creates incremented index-keys.
Is this the intended behaviour? Seems dangerous.
Jan, it's a little difficult to read your example. Can you use the pre and code tags to help Disqus keep from chopping up your code? See here: https://help.disqus.com/cus...
Thanks!
Sorry, was in a hurry there.
Any insights, Ben? I keep hitting "dangerous" situations when using array_column to index on columns where null can occur. I imagine that this might be a problem in many applications when more systems migrate to PHP 5.5
This isn't the intended behavior, but null also cannot be an array key. It gets converted to an empty string. In general, undefined things can happen if you use array_column() to index things by a column of data that doesn't contain all unique values.
Consider this example:
The null keys get converted to empty strings, and the second one overwrites the first, leaving an array that looks like:
So, going back to your example, you're expecting to see a resulting array that looks like this?
Let me know if that's correct. If so, I'll see what I can do to expedite a bug fix.
I would expect that result, yes. The existing behavior creates fictional keys that are indistinguishable from the real keys and thus can provide false positives that might cause a lot of trouble before discovered. Most custom indexing-functions also creates an empty string-key.
An interesting feature might be to use this key as a counter of truncated keys, but I'm not sure if the community would agree with this behavior :-) I'll leave it to the philosophers and the puritans in the field...
I have filed a bug report for this: https://bugs.php.net/bug.ph...
Please comment on the bug report if anything in it is inaccurate. Thanks!
Interestingly enough, HHVM already produces the correct output for array_column() that you expect. :-)