请记住,在 php 中,无论您使用什么函数,它最终都会转换为某种循环。
不过,您可以采取一些步骤来提高效率,这些步骤在 PHP 5.5 和 5.3/5.4 中是不同的。
PHP 5.3/5.4方式
最有效的方法是将函数拆分为两个单独的步骤。
第一步,您将为电子邮件列表生成键映射。
$keys = array();
foreach($emails as $k => $email)
{
$keys[$email->msgno] = $k;
}
在第二步中,您迭代多维 $threads 中的所有值并将它们替换为电子邮件详细信息:
// Iterate threads
$threads = array_map(function($thread) use($emails, $keys)
{
// Iterate emails in these threads
return array_map(function($msgno) use($emails, $keys)
{
// Swap the msgno with the email details
return $emails[$keys[$msgno]];
}, $thread);
}, $threads);
概念证明:http://pastebin.com/rp5QFN4J
关键词解释use在匿名函数中:
为了使用父作用域中定义的变量,可以使用以下命令将变量从父作用域导入到闭包作用域中:use ()关键词。尽管它是在 PHP 5.3 中引入的,但尚未在官方 PHP 手册中记录。这里只有 php 的 wiki 上的草稿文档https://wiki.php.net/rfc/closures#userland_perspective
PHP 5.5
此版本中的一项新功能使您可以使用生成器,它的内存指纹要小得多,因此效率更高。
关键词解释yield在发电机中:
生成器函数的核心是yield关键词。从最简单的形式来看,yield 语句看起来很像 return 语句,不同之处在于,yield 不是停止执行函数并返回,而是为循环生成器的代码提供一个值,并暂停生成器函数的执行。
第一步:
function genetateKeyMap($emails)
{
foreach($emails as $k => $email)
{
// Yielding key => value pair to result set
yield $email->msgno => $k;
}
};
$keys = iterator_to_array(genetateKeyMap($emails));
第二步:
function updateThreads($emails, $threads, $keys)
{
foreach($threads as $thread)
{
$array = array();
// Create a set of detailed emails
foreach($thread as $msgno)
{
$array[] = $emails[$keys[$msgno]];
}
// Yielding array to result set
yield $array;
}
};
$threads = iterator_to_array(updateThreads($emails, $threads, $keys));
关于生成器返回的值的几句话:
生成器返回一个对象,该对象是 SPL Iterator 的实例,因此它需要使用 iterator_to_array() 才能将其转换为与代码所期望的完全相同的数组结构。您不需要这样做,但需要在生成器函数之后更新代码,这可能会更有效。
概念证明:http://pastebin.com/9Z4pftBH
测试性能:
我生成了 7000 个线程的列表,每个线程有 5 条消息,并测试了每种方法的性能(5 次测试的平均值):
Takes: Memory used:
----------------------------
3x foreach(): 2.8s 5.2 MB
PHP 5.3/5.4 way 0.061s 2.7 MB
PHP 5.5 way 0.036s 2.7 MB
尽管您的计算机/服务器上的结果可能有所不同,但概述表明 2 步方法比使用 3 个 foreach 循环快大约 45-77 倍
测试脚本:http://pastebin.com/M40hf0x7