implementing multi-level "iterator" in PHP
I'm trying to create a iterator like this one, for a list of comments:
// the iterator class, pretty much the same as the one from the php docs...
abstract class MyIterator implements Iterator{
public $position = 0,
$list;
public function __constr开发者_如何学Gouct($list) {
$this->list = $list;
$this->position = 0;
}
public function rewind() {
$this->position = 0;
}
public function current() {
return $this->list[$this->position];
}
public function key() {
return $this->position;
}
public function next() {
++$this->position;
}
public function valid() {
return isset($this->list[$this->position]);
}
}
The comment iterator:
class MyCommentIterator extends MyIterator{
public function current(){
return new Comment($this->list[$this->position]);
}
}
And this is how I use it:
$comments = GetComments(); // gets the comments from the db
if($comments): ?>
<ol>
<?php foreach(new MyCommentIterator($comments) as $comment): ?>
<li>
<p class="author"><?php echo $comment->author(); ?></p>
<div class="content">
<?php echo $comment->content(); ?>
</div>
<!-- check for child comments and display them -->
</li>
<?php endforeach; ?>
</ol>
<?php endif; ?>
So everything is working fine, besides one thing: I can't figure it out how to process nested comments :(
The $comments
array returns a flat list of comments, like:
[0] => object(
'id' => 346,
'parent' => 0, // top level comment
'author' => 'John',
'content' => 'bla bla'
),
[1] => object(
'id' => 478,
'parent' => 346, // child comment of the comment with id =346
'author' => 'John',
'content' => 'bla bla'
)
...
I need to somehow be able to check for child comments (on multiple levels) and insert them before the </li>
's of their parent comments...
Any ideas?
Recursion is your friend.
displaycomment(comment):
$html .= "<ol>" . comment->html;
foreach comment->child:
$html .= "<li>" . displaycomment(child) . "</li>";
$html .= "</ol>";
return $html;
All code appearing in this post is pseudo. Any resemblance to real code, working or broken, is purely coincidental.
You might want to look into the RecursiveIterator
Interface PHP Manual. If you extend your iterator with the methods by that interface, you're able to iterate over your comments with an instance of RecursiveIteratorIterator
PHP Manual sequentially.
However as your output is a flat list, you need to take care of the logic for the levels on your own, e.g. inserting <ol>
per depth up, and </ol>
per depth down.
Use the flags to control the order how children are traversed.
You are using a flat array, but in reality, the items of that array are a tree or hierarchical data structure.
You are basically displaying a sequential list. Maybe you should construct a tree / hierarchical data structure first, without displaying, and later display data from the tree list.
/* array */ function FlatArrayToTreeArray(/* array */ $MyFlatArray)
{
...
}
/* void */ function IterateTree(/* array */ $MyTreeArray)
{
...
}
/* void */ function Example() {
$MyFlatArray = Array(
0 => object(
'id' => 346,
'parent' => 0, // top level comment
'author' => 'John',
'title' => 'Your restaurant food its too spicy',
'content' => 'bla bla'
),
1 => object(
'id' => 478,
'parent' => 346, // child comment of the comment with id =346
'author' => 'Mike',
'title' => 'Re: Your restaurant food its too spicy',
'content' => 'bla bla'
),
2 => object(
'id' => 479,
'parent' => 478, // child comment of the comment with id =346
'author' => 'John',
'title' => 'Re: Your restaurant food its too spicy',
'content' => 'bla bla'
),
3 => object(
'id' => 479,
'parent' => 346, // child comment of the comment with id =346
'author' => 'Jane',
'title' => 'Re: Your restaurant food its too spicy',
'content' => 'bla bla'
)
);
$MyTreeArray = FlatArrayToTreeArray($myflatarray);
IterateTree($MyTreeArray);
} // function Example()
Cheers.
精彩评论