Especially with Drupal 8 requiring PHP 5.4, closures (my brief intro) are going to much be much more useful and widespread. I would like to point out one advantage which already exists: array_walk($a, function (&$value, $key) {// some code here})
do not have any lingering after affects because both $value
and $key
are only visible in the scope of the closure. But foreach ($a as $key => &$value) { // same code here }
leaves $value a reference to the last item and it's guaranteed to give you some nasty, nasty surprises down the line. More, the behavior of foreach itself might change compared to the non reference using foreach ($a as $key => $value)
, read how foreach actually works for much more (and a bonus headache).
Also, the header of the closure strictly separates the body of the loop from the rest of the function / method where array_walk
is called, giving you a very clear overview of what might happen in the loop. For example
<?php
array_walk($this->databaseContents[$this->table], function (&$row_array) use ($fields, $condition, &$affected) {
?>
We immediately know that the function might change the array values, will use the $fields and $condition variables and also change the $affected variable. We know that $fields and $condition can not change within this loop. This might not be visible even when reading the loop because it is possible that you have a function call:
<?php
array_walk($this->databaseContents[$this->table], function (&$row_array) use ($fields, $condition, &$affected) {
$row = new DatabaseRow($row_array);
if (ConditionResolver::matchGroup($row, $condition)) {
?>
and without looking up matchGroup
it is not possible to know whether it takes $condition
by reference -- so just reading the code does not tell you what variables change and which ones are immutable. (And yes, objects passed around by handle and changing all the time is a bummer on this.)
Commenting on this Story is closed.
Closures are indeed nice`n`warm`n`fuzzy, but everyone should remeber that they come with a performance penalty [1] [2], so be careful with unnecessary usage.
[1] http://willem.stuursma.name/2010/11/22/a-detailed-look-into-array_map-an...
[2] http://www.faieta.net/wp/performance-implications-of-closures-in-php/
amateescu
I'm not saying there's no performance penalty, as it makes sense that there would be (and the benchmarks suggest that, yes, there is) - but it's meaningless in a huge DB-driven, network-heavy application like most web apps are.
If it takes twice as long to do the closure, but makes your code safer or architecturally better, and "twice as long" equates to about 6ms vs 3ms per iteration, you take that penalty 95% of the time. If your app is doing intense processing, you may indeed need to opt for speed over flexibility or safety. But this is the rare case, and honestly you should be looking into building a C extension, not PHP, if you actually need every millisecond squeezed out of a particular algorithm.
I just did a benchmark about this a few days ago, and the closure results are definitely apalling. Specifically, for the same loop, I compared use of
Results vary from machine to machine and even have some variation on the same machine, but using PHP 5.3.11, they consistently fall in three performance groups, in normalized units of time to accomplish the same task (so lower is better)
Yes, using closures as callbacks for array_map operations is more than 6 times slower than a plain old loop, and even more than three times slower than using array_map with a class/instance method.
To some degree, it makes sense since closures carry an environment along with the code while the other solutions don't. But still...
fgm