PHP从多维数组(IMAP)创建消息线程的多维数组 [英] PHP creating a multidimensional array of message threads from a multidimensional array (IMAP)

查看:114
本文介绍了PHP从多维数组(IMAP)创建消息线程的多维数组的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我的问题如下:

如果你看下面你会看到有一个包含消息ID的数据结构,然后是最终的数据结构,其中包含消息详细信息从 imap_fetch_overview 汇总。消息ID来自 imap_thread 。问题是它没有将邮件的详细信息放在邮件ID的位置。

If you look below you'll see there is a datastructure with message ids and then the final datastructure containing the message details which should be aggregated from imap_fetch_overview. The message ids are from imap_thread. The problem is its not putting the email details in the position where the message id is.

这是我的数据结构:

[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
    )

以下是我到目前为止的代码:

Here is the code I have thus far:

$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;
          }
      }
    }
 }

是从其中一封电子邮件打印输出:

Here is a printout from one of the $emails:

    [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 ,所以在技术上,数据应该填充到最终的数据结构中。

If you notice, the msgno is 5 which corrolates to the $id, so technically the data should be populating into the final datastructure.

此外,这似乎是一种低效的方式来处理这个问题。

Also, this seems like an inefficient way to handle this.

如果您需要任何其他说明,请通知我。

Please let me know if I you need any additional clarification.

更新代码

Thi s代码是我在php api和我修复的一些代码的组合。我认为有问题的仍然是 $ root

This code is a combination of code I found on php api and some fixes by me. What I think is problematic still is the $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中有所不同。

Remember that in php whatever function you use it will be finally converted to some sort of loop. There are, however some steps you could take to make it more efficient and they are different in PHP 5.5 and in 5.3/5.4.

最有效的方式是将功能拆分为两个独立的步骤。
在第一步,您将生成电子邮件列表的键映射。

The most efficient way of doing this would be to split the function to 2 separate steps. In first step you would generate a map of keys for the list of emails.

$keys = array();
foreach($emails as $k => $email)
{
    $keys[$email->msgno] = $k;
}

在第二步中,迭代多维$线程中的所有值,并替换他们与电子邮件的详细信息:

In 2nd step you iterate all values in the multi-dimensional $threads and replace them with the email details:

// 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

匿名函数中关键字使用的说明:

Explanation of keyword use in anonymous functions:

为了使用父范围中定义的变量,可以使用 use()关键字。虽然它是在PHP 5.3中引入的,但还没有在官方的PHP手册中记录。这里只有一个关于php wiki的草稿文档。 https://wiki.php.net/rfc/closures# userland_perspective

In order to make use of variables defined in the parent scope, it is possible to import variables from the parent scope into the closure scope with the use () keyword. Although it was introduced in PHP 5.3 it hasn't been documented in the official PHP manual yet. There's only a draft document on php's wiki here https://wiki.php.net/rfc/closures#userland_perspective

此版本的其中一个新功能可让您使用生成器,其具有明显更小的内存指纹,因此更有效。

One of the new features in this version enables you to use generators, which have significantly smaller memory thumbprint thus are more efficient.

生成器中关键字收益的说明

生成函数的核心是 yield 关键字。在其最简单的形式中,yield语句看起来就像一个return语句,除了代替停止执行函数并返回的代码之外,yield代替为循环发生器的代码提供一个值,并暂停生成器函数的执行。

The heart of a generator function is the yield keyword. In its simplest form, a yield statement looks much like a return statement, except that instead of stopping execution of the function and returning, yield instead provides a value to the code looping over the generator and pauses execution of the generator function.

第一步:

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));

关于genrators返回值的几个字:

A few words about the values being returned by genrators:

生成器返回一个对象,该对象是SPL Iterator的一个实例,因此需要使用iterator_to_array()才能将其转换为与代码所期望的完全相同的数组结构。您不需要这样做,但是需要在生成器函数之后更新代码,这可能更有效。

Generators return an object which is an instance of SPL Iterator thus it needs to use iterator_to_array() in order to convert it into exactly the same array structure your code is expecting. You don't need to do this, but it would require an update of your code following the generator function, which could be even more efficient.

概念证明: a href =http://pastebin.com/9Z4pftBH =nofollow> http://pastebin.com/9Z4pftBH

Proof of concept: http://pastebin.com/9Z4pftBH

我生成了7000个线程的列表,每个线程有5个消息,并测试了每个方法的性能(平均来自5个测试):

I generated a list of 7000 threads with 5 messages each and tested the performance of each method (avg from 5 tests):

                   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倍循环

Although the results on your machine/server might be different but the overview shows that the 2-step method is around 45-77 times faster than using 3 foreach loops

测试脚本: h ttp://pastebin.com/M40hf0x7

这篇关于PHP从多维数组(IMAP)创建消息线程的多维数组的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆