我的问题如下:
如果你看下面你会看到有一个带有消息ID的数据结构,然后是包含应该从imap_fetch_overview汇总的消息详细信息的最终数据结构.消息ID来自imap_thread.问题是它没有将电子邮件详细信息放在消息ID所在的位置.
这是我的数据结构:
[5] => Array
(
[0] => 5
[1] => 9
)
[10] => Array
(
[0] => 10
[1] => 11
)
我想拥有的是:
[5] => Array
(
[0] => messageDetails for id 5
[1] => messageDetails for id 9
)
[10] => Array
(
[0] => messageDetails for id 10
[1] => messageDetails for id 11
)
这是我到目前为止的代码:
$emails = imap_fetch_overview($imap, implode(',',$ids));
// root is the array index position of the threads message, such as 5 or 10
foreach($threads as $root => $messages){
// id is the id being given to us from `imap_thread`
foreach($message as $key => $id){
foreach($emails as $index => $email){
if($id === $email->msgno){
$threads[$root][$key] = $email;
break;
}
}
}
}
这是来自$email之一的打印输出:
[0] => stdClass Object
(
[subject] => Cloud Storage Dump
[from] => Josh Doe
[to] => jondoe@domain.com
[date] => Mon, 21 Jan 2013 23:18:00 -0500
[message_id] => <50FE12F8.9050506@domain.com>
[size] => 2559
[uid] => 5
[msgno] => 5
[recent] => 0
[flagged] => 0
[answered] => 1
[deleted] => 0
[seen] => 0
[draft] => 0
[udate] => 1358828308
)
如果你注意到,msgno是5,它会腐蚀到$id,所以从技术上讲,数据应该填充到最终的数据结构中.
而且,这似乎是一种处理此问题的低效方法.
如果您需要任何其他说明,请告诉我.
更新代码
这段代码是我在PHP api上找到的代码和我的一些修复的组合.我认为有问题的仍然是$root.
$addedEmails = array();
$thread = imap_thread($imap);
foreach ($thread as $i => $messageId) {
list($sequence, $type) = explode('.', $i);
//if type is not num or messageId is 0 or (start of a new thread and no next) or is already set
if($type != 'num' || $messageId == 0 || ($root == 0 && $thread[$sequence.'.next'] == 0) || isset($rootValues[$messageId])) {
//ignore it
continue;
}
if(in_array($messageId, $addedEmails)){
continue;
}
array_push($addedEmails,$messageId);
//if this is the start of a new thread
if($root == 0) {
//set root
$root = $messageId;
}
//at this point this will be part of a thread
//let's remember the root for this email
$rootValues[$messageId] = $root;
//if there is no next
if($thread[$sequence.'.next'] == 0) {
//reset root
$root = 0;
}
}
$ids=array();
$threads = array();
foreach($rootValues as $id => $root){
if(!array_key_exists($root,$threads)){
$threads[$root] = array();
}
if(!in_array($id,$threads[$root])){
$threads[$root][] = $id;
$ids[]=$id;
}
}
$emails = imap_fetch_overview($imap, implode(',', array_keys($rootValues)));
$keys = array();
foreach($emails as $k => $email)
{
$keys[$email->msgno] = $k;
}
$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);
解决方法:
请记住,在PHP中,无论你使用什么函数,它都会最终转换为某种循环.
但是,您可以采取一些步骤来提高效率,它们在PHP 5.5和5.3 / 5.4中有所不同.
PHP 5.3 / 5.4方式
最有效的方法是将功能拆分为2个单独的步骤.
在第一步中,您将生成电子邮件列表的键映射.
$keys = array();
foreach($emails as $k => $email)
{
$keys[$email->msgno] = $k;
}
在第二步中,您迭代多维$线程中的所有值,并将其替换为电子邮件详细信息:
// 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()关键字将变量从父作用域导入到闭包作用域中.虽然它是在PHP 5.3中引入的,但尚未在官方PHP手册中记录.这里只有关于PHP维基的草案文件https://wiki.php.net/rfc/closures#userland_perspective
PHP 5.5
此版本的新功能之一使您可以使用生成器,它具有明显更小的内存指纹,因此更有效.
生成器中关键字产量的说明:
生成器函数的核心是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_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
虽然您的机器/服务器上的结果可能不同,但概述显示两步法比使用3个foreach循环快约45-77倍
测试脚本:http://pastebin.com/M40hf0x7
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。