【问题标题】:Nested while loops嵌套的while循环
【发布时间】:2011-08-11 22:37:42
【问题描述】:

我有一个 cmets 系统。每个评论都可能收到回复,每个回复都可能收到回复,令人作呕。

因此,我的数据库包含一个名为“cmets”的表,其中包含以下重要字段:

id
text
reply_to

...在reply_to 下,当然是作为回复的评论的ID。

所以现在,问题很简单:我如何显示所有的 cmets,但要知道在每个评论之后必须对它进行回复,并且在每个回复之后必须对回复进行回复,等等?

我尝试最多的,以及我不断重复的,是这样的:

$query = mysql_query("SELECT * FROM comments WHERE reply_to=0");
while ($comment = mysql_fetch_array($query))
    include("comment.php");

在comment.php中,我拥有的是:

foreach ($comment as $key = $value) $$key = $value;
echo $text;
echo "<div style='margin-left:30px;'>"; //A margin for a little indent
$subquery = mysql_query("SELECT * FROM comments WHERE reply_to=$id");
while ($comment = mysql_fetch_array($subquery))
    include("comment.php");
echo "</div>";

但是如果我正确地复制了我的代码的本质,问题是:在第一个回复被回显之后,它继续到第一个回复的第一个回复,然后是第一个回复的第一个回复第一个回复,但循环永远不会得到任何第二个回复。所以举个例子,假设表有 3 个 cmets,每个 cmets 有 3 个回复,每个有 3 个回复,等等,上面的代码会输出:

Comment
  First reply
    First second-order reply
      First third-order reply
        ...

我希望我已经解释得足够清楚了。 inb4:我无法向表中添加新列。

【问题讨论】:

  • 您需要将代码打包到一个函数中,并使其递归。 stackoverflow.com/questions/2648968/…
  • 如果不出意外,上床睡觉,醒来后的几个小时内不要想代码。如果您整天都在为此苦苦挣扎,请离开一会儿。
  • 循环访问数据库也不是一个好主意。 id 在 1 个查询中获取所有相关的 cmets,然后尝试使用循环/递归显示它们。
  • 使用心理计算机科学技能我可以说这是递归的经典案例

标签: php while-loop


【解决方案1】:

在伪代码中:

function display_comment(comm)
  echo comm's info and text
  children = get children of the comment: SELECT from comments WHERE parent = (comm's id)
  echo <div class="comment-thread">
  foreach children as child
    display_comment(comm) // notice this line
  echo </div>

您必须创建一个函数,以使其递归引用。

【讨论】:

    【解决方案2】:
    $subquery = mysql_query(SELECT * FROM comments WHERE reply_to=$comment_id);
    

    可能是一些错误。当你描述你的表定义时,带有评论 ID 的字段被命名为id,但这里你使用的是comment_id。此外,您的 SQL 语句没有用引号 (' ') 括起来。是复制粘贴相关的错误吗?

    【讨论】:

      【解决方案3】:

      我通常这样做

        function get_comments($text_id, $parent_id,$depth){
               $sql="SELECT * FROM spam WHERE parent_id='".(int)$parent_id."' AND text_id='".(int)$text_id."' ";
               //..query 
               while ($row=mysql_fetch_assoc($query)){
                   //some comment output use $depth*pixels to indent
                   $depth++; 
                   get_comments($text_id,$row['parent_id'],$depth);
                   $depth--;
      
               }
      
        }
      

      在第一次通话中

        get_comments($text_id,0,0); //
      

      【讨论】:

      • 在循环中执行未准备好的 SQL 语句真的很糟糕。
      • 我只发布了这个作为递归循环的例子,而不是 sql。我假设他在存储在 db 中的 id 之前清理了它,并且应该是整数并且已经清理了。但改变了我的帖子
      • SQL 语句已经在循环中 :) 关于准备好的语句 - dev.mysql.com/doc/refman/5.5/en/… , php.net/manual/en/mysqli.prepare.php
      • 啊,谢谢你的信息,一开始我不明白你的意思。但我想知道您是否使用 Chris answer 将所有数据存储在变量中,您将如何处理大型数据库与您需要的内存?
      • 如果你有很大的cmets数据库,当然你需要部分打印出来。例如,您可以将帖子的整个 cmets 列表分成几页。
      【解决方案4】:

      如果您还包含一个深度列,您的生活会轻松一些。

      http://www.devx.com/tips/Tip/22127

      【讨论】:

        【解决方案5】:

        嗯,有趣的东西。所以这是我的想法(这是一个设计问题,所以我猜有很多方法)。就我个人而言,我会使用字典来表示父 cmets。这是我如何处理的一些伪代码:

        首先是数据库:

        +--------------------------+
        | comments                 |
        +--------------------------+
        | id (INT)                 | <-- a unique id for the comment
        | post_id (INT)            | <-- the original post / article being replied to
        | parent_id (INT)          | <-- the comment this is in response to
        | commenter_email (VARCHAR)| <-- just some way to identify the commenter
        | comment_text (TEXT)      | <-- the actual comment
        +--------------------------+
        

        第二个伪代码:

        function print_comment($comment_id, $replies_children, $comments)
        {
            // For every comment at this level...
            foreach($reply_id in $replies_children[$comment_id])
            {
                // Create a div container to contain both this comment AND
                // all child comments. We let CSS take care of indenting.
                echo '<div style="padding-left: 10px;">';
        
                // Print this comment first...
                echo $comments[$reply_id]['comment_text'];
        
                // And beneath it print all of the replies to this comment
                print_comment($reply_id, $replies_children, $comments);
        
                // Finally end this level of comment indentation
                echo '</div>';
            }
        }
        
        // Fetch all of the comments at once for post id 10
        $sql = "SELECT * FROM comments WHERE post_id = 10;";
        
        // Get the results back (associative array, please)
        $results = execute_sql($sql);
        
        // Holds a list of replies (comment ids) for each comment
        $replies_children = array();
        
        // Lets us map an ID to the actual full sql result
        $comments = array();
        
        foreach($result in $results)
        {
            // Make sure there's a list for the parent
            if($replies_children doesnt have key $result['parent_id']))
                $replies_children[$results['parent_id']] = array();
        
            // Append this item to the parent's list
            $replies_children[$result['parent_id']][] = $result['id'];
        
            // Allows us to get to this result by id directly
            $comments[$result['id']] = $result;
        }
        
        // Assume that id = 0 is the root level
        print_comment(0, $replies_children, $comments);
        

        这样你只调用一次数据库。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2023-03-06
          • 2014-03-25
          相关资源
          最近更新 更多