PHP中使用迭代的嵌套注释

PHP中使用迭代的嵌套注释,php,arrays,iterator,Php,Arrays,Iterator,我目前正在使用PHP开发一个评论系统,我正在使用“父ID”解决方案将一个回复连接到另一个回复。问题是我还没有弄清楚如何将存储在mysql中的这些“父ID”连接数据转换到PHP数组并呈现出来。我一直在搜索迭代解决方案,但没有找到任何结果。我的数据库结构如下: 父项id 0表示顶级注释 comment_id content parent_id 1 xxx 0 2 xxx 0 3 xxx 1 4 xxx

我目前正在使用PHP开发一个评论系统,我正在使用“父ID”解决方案将一个回复连接到另一个回复。问题是我还没有弄清楚如何将存储在mysql中的这些“父ID”连接数据转换到PHP数组并呈现出来。我一直在搜索迭代解决方案,但没有找到任何结果。我的数据库结构如下: 父项id 0表示顶级注释

comment_id content parent_id
1          xxx     0
2          xxx     0
3          xxx     1
4          xxx     3
5          xxx     4
6          xxx     3
...        ...     ...
下面是我所做的,我将所有注释提取到一个数组中,该数组如下所示:

$comment_list = array(0=>array('comment_id'=>1,'content'=>'xxx','parent_id'=>0),
                      0=>array('comment_id'=>2,'content'=>'xxx','parent_id'=>0),
                      0=>array('comment_id'=>3,'content'=>'xxx','parent_id'=>1),
                      0=>array('comment_id'=>4,'content'=>'xxx','parent_id'=>3),
                      ...

)
//these definition files get hidden and tucked away for future use
//you use include, include_once, require, or require_once to load them
class CommentFactory{
      /**** other Code *****/

      public function createCommentArrayFromDatabaseRecords( $records ){
                  /*** add the data conversion here that we discussed above ****/
                  return $workingMemory;
      }
}
class HTMLFactory{
       public function makeCommentTableFromCommentArray( $array ){
            $htmlString = "";
            foreach( $array as $comment ){
                 if( $comment->isRoot ){
                        $htmlString .= $this->getHTMLStringForComment( $comment );
                 }
            }
            return $htmlString;
       }
       private function getHTMLStringForComment( $comment, $level=0 ){
            /*** turn your comment and all it's children into HTML here (recursively) ****/
            return $html;
       }
}
//let database be a mysqli or other database connection
//let the query function be whatever method works for your database
// of choice.
//let the $fetch_comment_sql variable hold your SQL string to fetch the
//   comments
$records = $database->query( $fetch_comment_sql )
$comFactory = new CommentFactory();
$commentArray = $comFactory->createCommentArrayFromDatabaseRecords( $records );
$htmlFactory = new HTMLFactory();
$htmlResult = $htmlFactory->makeCommentTableFromCommentArray( $commentArray );
echo $htmlResult;

我需要附加带有parent_id 1的注释来添加带有comment_id 1的注释,以此类推,深度应该是无限的,而且工作了几个小时仍然找不到正确迭代的方法,有人能给我一些如何做的建议吗?我知道一个解决方案,但每次迭代都会向数据库发出新的请求,所以我更喜欢一次性使用PHP数组,谢谢

当面对这样复杂的结构时,有时最好创建一个面向对象的解决方案,然后使用对象创建所需的数组

例如,基于上述内容,我可以定义以下类:

class Comment{
    protected $id;
    protected $children;
    protected $content;

    public function __construct( $id, $content ){
        $this->id = $id;
        $this->content = $content;
        $this->children = array();
    }
    public function addChild( $child ){
        $this->children[] = $child;
    }
}
现在,我们使用此对象将数据库传输到工作内存中,如下所示:

$workingMemory = array(); //a place to store our objects
$unprocessedRows = array(); //a place to store unprocessed records

// here, add some code to fill $unproccessedRows with your database records

do{
  $row = $unprocessedRows; //transfer unprocessed rows to a working array
  $unprocessedRows = array(); //clear unprocessed rows to receive any rows that we need to process out of order.
  foreach( $row as $record ){
    $id = $record[0]; //assign your database value for comment id here.
    $content = $record[1]; //assign your database value for content here.
    $parentId = $record[2]; //assign your database value for parent id here

    $comment = new Comment( $id, $content );

    //for this example, we will refer to unlinked comments as 
    //having a parentId === null.
    if( $parentId === null ){
         //this is just a comment and does not need to be linked to anything, add it to working memory indexed by it's id.
         $workingMemory[ $id ] = $comment;
    }else if( isset( $workingMemory[ $parentId ] ) ){
         //if we are in this code block, then we processed the parent earlier.
         $parentComment = $workingMemory[ $parentId ];
         $parentComment->addChild( $comment );
         $workingMemory[ $id] = $comment;
    }else{
         //if we are in this code block, the parent has not yet been processed. Store the row for processing again later.
         $unprocessedRows[] = $record;
    }

   }
  }while( count( $unprocessedRows ) > 0 );
function outputCommentToHTML( $aComment, $commentLevel = 0 ){
    //I am using commentLevel here to set a special class, which I would use to indent the sub comments.
    echo "<span class'comment {$commentLevel}' id='".($aComment->getId())."'>".($aComment->getContent())."</span>";
    $children = $aComment->getChildren();
    foreach( $children as $child ){
         outputCommentToHTML( $child, $commentLevel + 1 );
    }
}
foreach( $workingMemory as $aComment ){
    if( $aComment->isRoot === true ){
         outputCommentToHTML( $aComment );
    }
}
完成所有未处理的行后,注释的表示形式将完全存储在变量$workingMemory中,并且此数组的每个单元格都是一个注释对象,具有$id、$content和指向所有子$comments的链接

我们现在可以遍历这个数组,并生成我们想要的任何数据数组或表。我们必须记住,按照存储数组的方式,我们可以直接从$workingMemory数组访问任何注释

如果我使用它为网站生成HTML,我会循环遍历workingMemory数组,只处理父注释。然后,每个进程都将遍历子进程。从父母而不是孩子开始,我们保证不会重复处理同一条评论

我会修改我的注释类,使之更容易:

class Comment{
    protected $id;
    protected $children;
    protected $content;
    protected $isRoot;

    public function __construct( $id, $content ){
        $this->id = $id;
        $this->content = $content;
        $this->children = array();
        $this->isRoot = true;
    }
    public function addChild( $child ){
        $child->isRoot = false;
        $this->children[] = $child;
    }
    public function getChildren(){ return $this->children; }
    public function getId(){ return $this->id; }
    public function getContent(){ return $this->content; }
}
更改后,我可以按如下方式创建HTML:

$workingMemory = array(); //a place to store our objects
$unprocessedRows = array(); //a place to store unprocessed records

// here, add some code to fill $unproccessedRows with your database records

do{
  $row = $unprocessedRows; //transfer unprocessed rows to a working array
  $unprocessedRows = array(); //clear unprocessed rows to receive any rows that we need to process out of order.
  foreach( $row as $record ){
    $id = $record[0]; //assign your database value for comment id here.
    $content = $record[1]; //assign your database value for content here.
    $parentId = $record[2]; //assign your database value for parent id here

    $comment = new Comment( $id, $content );

    //for this example, we will refer to unlinked comments as 
    //having a parentId === null.
    if( $parentId === null ){
         //this is just a comment and does not need to be linked to anything, add it to working memory indexed by it's id.
         $workingMemory[ $id ] = $comment;
    }else if( isset( $workingMemory[ $parentId ] ) ){
         //if we are in this code block, then we processed the parent earlier.
         $parentComment = $workingMemory[ $parentId ];
         $parentComment->addChild( $comment );
         $workingMemory[ $id] = $comment;
    }else{
         //if we are in this code block, the parent has not yet been processed. Store the row for processing again later.
         $unprocessedRows[] = $record;
    }

   }
  }while( count( $unprocessedRows ) > 0 );
function outputCommentToHTML( $aComment, $commentLevel = 0 ){
    //I am using commentLevel here to set a special class, which I would use to indent the sub comments.
    echo "<span class'comment {$commentLevel}' id='".($aComment->getId())."'>".($aComment->getContent())."</span>";
    $children = $aComment->getChildren();
    foreach( $children as $child ){
         outputCommentToHTML( $child, $commentLevel + 1 );
    }
}
foreach( $workingMemory as $aComment ){
    if( $aComment->isRoot === true ){
         outputCommentToHTML( $aComment );
    }
}
它将以HTML格式输出:

  Comment_1
      Comment_3
           Comment_4
                Comment_5
           Comment_6
  Comment_2
这是在函数中递归完成的,该函数在移动到注释2之前完全处理注释1。在转到注释2之前,它还完全处理注释3,这就是注释4、5和6在注释2之前都得到输出的方式

上面的例子对您很有用,但是如果它是我的个人项目,我不会混合线性和面向对象的代码,所以我会创建一个代码工厂来将注释转换为HTML。工厂从源对象生成数据字符串。您可以创建一个充当HTML工厂的对象,以及另一个充当SQL生成器的工厂,通过使用类似于这样的解决方案分层对象,您可以创建一个完全面向对象的解决方案,普通读者甚至非编码人员更容易理解该解决方案,从而生成类似以下内容:

$comment_list = array(0=>array('comment_id'=>1,'content'=>'xxx','parent_id'=>0),
                      0=>array('comment_id'=>2,'content'=>'xxx','parent_id'=>0),
                      0=>array('comment_id'=>3,'content'=>'xxx','parent_id'=>1),
                      0=>array('comment_id'=>4,'content'=>'xxx','parent_id'=>3),
                      ...

)
//these definition files get hidden and tucked away for future use
//you use include, include_once, require, or require_once to load them
class CommentFactory{
      /**** other Code *****/

      public function createCommentArrayFromDatabaseRecords( $records ){
                  /*** add the data conversion here that we discussed above ****/
                  return $workingMemory;
      }
}
class HTMLFactory{
       public function makeCommentTableFromCommentArray( $array ){
            $htmlString = "";
            foreach( $array as $comment ){
                 if( $comment->isRoot ){
                        $htmlString .= $this->getHTMLStringForComment( $comment );
                 }
            }
            return $htmlString;
       }
       private function getHTMLStringForComment( $comment, $level=0 ){
            /*** turn your comment and all it's children into HTML here (recursively) ****/
            return $html;
       }
}
//let database be a mysqli or other database connection
//let the query function be whatever method works for your database
// of choice.
//let the $fetch_comment_sql variable hold your SQL string to fetch the
//   comments
$records = $database->query( $fetch_comment_sql )
$comFactory = new CommentFactory();
$commentArray = $comFactory->createCommentArrayFromDatabaseRecords( $records );
$htmlFactory = new HTMLFactory();
$htmlResult = $htmlFactory->makeCommentTableFromCommentArray( $commentArray );
echo $htmlResult;
如果操作正确,它可以清理您的活动代码文件,使其读起来几乎像以下指令列表:

$comment_list = array(0=>array('comment_id'=>1,'content'=>'xxx','parent_id'=>0),
                      0=>array('comment_id'=>2,'content'=>'xxx','parent_id'=>0),
                      0=>array('comment_id'=>3,'content'=>'xxx','parent_id'=>1),
                      0=>array('comment_id'=>4,'content'=>'xxx','parent_id'=>3),
                      ...

)
//these definition files get hidden and tucked away for future use
//you use include, include_once, require, or require_once to load them
class CommentFactory{
      /**** other Code *****/

      public function createCommentArrayFromDatabaseRecords( $records ){
                  /*** add the data conversion here that we discussed above ****/
                  return $workingMemory;
      }
}
class HTMLFactory{
       public function makeCommentTableFromCommentArray( $array ){
            $htmlString = "";
            foreach( $array as $comment ){
                 if( $comment->isRoot ){
                        $htmlString .= $this->getHTMLStringForComment( $comment );
                 }
            }
            return $htmlString;
       }
       private function getHTMLStringForComment( $comment, $level=0 ){
            /*** turn your comment and all it's children into HTML here (recursively) ****/
            return $html;
       }
}
//let database be a mysqli or other database connection
//let the query function be whatever method works for your database
// of choice.
//let the $fetch_comment_sql variable hold your SQL string to fetch the
//   comments
$records = $database->query( $fetch_comment_sql )
$comFactory = new CommentFactory();
$commentArray = $comFactory->createCommentArrayFromDatabaseRecords( $records );
$htmlFactory = new HTMLFactory();
$htmlResult = $htmlFactory->makeCommentTableFromCommentArray( $commentArray );
echo $htmlResult;

当前如何从数据库中取出阵列?还有,你是如何将你的评论链接到某个东西的。。。这是没有价值的。