这三种方法(都用于将一个数组转换为另一个数组)之间的性能差异(如果有)是什么?
foreach
array_map
为了使自己清楚,让我们看一下这些示例,它们都做同样的事情-将数字数组乘以10:
$numbers = range(0, 1000);
佛瑞奇
$result = array(); foreach ($numbers as $number) { $result[] = $number * 10; } return $result;
带有lambda的地图
return array_map(function($number) { return $number * 10; }, $numbers);
具有“静态”功能的地图,作为字符串引用传递
function tenTimes($number) { return $number * 10; } return array_map('tenTimes', $numbers);
还有其他方法吗?我将很高兴听到上面案例之间的 所有 实际差异,以及为什么要使用一个案例代替其他案例的任何输入。
FWIW,我只是做了基准测试,因为海报没有做到。在PHP 5.3.10 + XDebug上运行。
更新2015年1月22日与下面的mcfedr的答案进行比较,以获得没有XDebug和更新的PHP版本的其他结果。
function lap($func) { $t0 = microtime(1); $numbers = range(0, 1000000); $ret = $func($numbers); $t1 = microtime(1); return array($t1 - $t0, $ret); } function useForeach($numbers) { $result = array(); foreach ($numbers as $number) { $result[] = $number * 10; } return $result; } function useMapClosure($numbers) { return array_map(function($number) { return $number * 10; }, $numbers); } function _tenTimes($number) { return $number * 10; } function useMapNamed($numbers) { return array_map('_tenTimes', $numbers); } foreach (array('Foreach', 'MapClosure', 'MapNamed') as $callback) { list($delay,) = lap("use$callback"); echo "$callback: $delay\n"; }
在十几次尝试中,我得到了与100万个数字相当一致的结果:
假设关闭时地图的缓慢运行是由于每次可能都会评估关闭而造成的,我还进行了如下测试:
function useMapClosure($numbers) { $closure = function($number) { return $number * 10; }; return array_map($closure, $numbers); }
但是结果是相同的,证实了闭包只被评估了一次。
2014年2月2日更新:操作码转储
这是三个回调的操作码转储。第一useForeach():
useForeach()
compiled vars: !0 = $numbers, !1 = $result, !2 = $number line # * op fetch ext return operands --------------------------------------------------------------------------------- 10 0 > EXT_NOP 1 RECV 1 11 2 EXT_STMT 3 INIT_ARRAY ~0 4 ASSIGN !1, ~0 12 5 EXT_STMT 6 > FE_RESET $2 !0, ->15 7 > > FE_FETCH $3 $2, ->15 8 > OP_DATA 9 ASSIGN !2, $3 13 10 EXT_STMT 11 MUL ~6 !2, 10 12 ASSIGN_DIM !1 13 OP_DATA ~6, $7 14 14 > JMP ->7 15 > SWITCH_FREE $2 15 16 EXT_STMT 17 > RETURN !1 16 18* EXT_STMT 19* > RETURN null
然后 useMapClosure()
useMapClosure()
compiled vars: !0 = $numbers line # * op fetch ext return operands --------------------------------------------------------------------------------- 18 0 > EXT_NOP 1 RECV 1 19 2 EXT_STMT 3 EXT_FCALL_BEGIN 4 DECLARE_LAMBDA_FUNCTION '%00%7Bclosure%7D%2Ftmp%2Flap.php0x7f7fc1424173' 21 5 SEND_VAL ~0 6 SEND_VAR !0 7 DO_FCALL 2 $1 'array_map' 8 EXT_FCALL_END 9 > RETURN $1 22 10* EXT_STMT 11* > RETURN null
及其调用的闭包:
compiled vars: !0 = $number line # * op fetch ext return operands --------------------------------------------------------------------------------- 19 0 > EXT_NOP 1 RECV 1 20 2 EXT_STMT 3 MUL ~0 !0, 10 4 > RETURN ~0 21 5* EXT_STMT 6* > RETURN null
然后useMapNamed()函数:
useMapNamed()
compiled vars: !0 = $numbers line # * op fetch ext return operands --------------------------------------------------------------------------------- 28 0 > EXT_NOP 1 RECV 1 29 2 EXT_STMT 3 EXT_FCALL_BEGIN 4 SEND_VAL '_tenTimes' 5 SEND_VAR !0 6 DO_FCALL 2 $0 'array_map' 7 EXT_FCALL_END 8 > RETURN $0 30 9* EXT_STMT 10* > RETURN null
以及它调用的命名函数_tenTimes():
_tenTimes()
compiled vars: !0 = $number line # * op fetch ext return operands --------------------------------------------------------------------------------- 24 0 > EXT_NOP 1 RECV 1 25 2 EXT_STMT 3 MUL ~0 !0, 10 4 > RETURN ~0 26 5* EXT_STMT 6* > RETURN null