首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >使用PHP的迭代器的嵌套列表?

使用PHP的迭代器的嵌套列表?
EN

Stack Overflow用户
提问于 2012-02-28 09:10:53
回答 5查看 2.5K关注 0票数 6

我正在尝试显示这样的数组:

代码语言:javascript
运行
复制
$nodes = array(

  1 => array(
         'title'    => 'NodeLvl1',
         'children' => array(),
       ),    
  2 => array(
         'title'    => 'NodeLvl1',
         'children' => array(        
                         1 => array(
                                'title'    => 'NodeLvl2',
                                'children' => array(),
                             ),    
                         2 => array(
                                'title'    => 'NodeLvl2',
                                'children' => array(


                                   1 => array(
                                          'title'    => 'NodeLvl3',
                                          'children' => array(),
                                       ),


                                   2 => array(
                                          'title'    => 'NodeLvl3',
                                          'children' => array(),
                                       ),    
                                ),
                              ),    

                       ),
       ),

  3 => array(
         'title'    => 'NodeLvl1',
         'children' => array(),
       ),    
);

如下所示:

代码语言:javascript
运行
复制
<ul>
  <li>
    NodeLvl1
  </li>
  <li>
    NodeLvl1
      <ul>
        <li>NodeLv2</li>
         ...

      </ul>
  </li>
  ...

基本上是一个考虑了“孩子”属性的嵌套列表。到目前为止,我已经想出了这个:

代码语言:javascript
运行
复制
class It extends RecursiveIteratorIterator{

  protected
    $tab    = "\t";

  public function beginChildren(){

    if(count($this->getInnerIterator()) == 0)
      return;

    echo str_repeat($this->tab, $this->getDepth())."<ul>\n";
  }

  public function endChildren(){


    if(count($this->getInnerIterator()) == 0)
      return;

    echo str_repeat($this->tab, $this->getDepth())."\n</ul>";
  }

  public function nextElement(){
    echo str_repeat($this->tab, $this->getDepth() + 1).'<li>';
  }

}

$it = new It(new RecursiveArrayIterator($nodes));

foreach($it as $key => $item)
  echo $item;

这并不能很好地工作:我将每个项目包装在<ul>s之间,但我不知道如何关闭<li>s……

有没有关于如何让它工作的想法?另外,是否可以获取所有数组属性(实际元素),而不仅仅是foreach()循环中的"title“属性?这可以用对象而不是数组来完成吗?

EN

回答 5

Stack Overflow用户

回答已采纳

发布于 2012-03-02 03:55:59

您可以使用RecursiveCachingIterator来做您想做的事情。这里有一个例子,(来源:https://github.com/cballou/PHP-SPL-Iterator-Interface-Examples/blob/master/recursive-caching-iterator.php)

代码语言:javascript
运行
复制
<?php
// example navigation array
$nav = array(
    'Home' => '/home',
    'Fake' => array(
        'Double Fake' => array(
            'Nested Double Fake' => '/fake/double/nested',
            'Doubly Nested Double Fake' => '/fake/double/doubly'
        ),
        'Triple Fake' => '/fake/tripe'
    ),
    'Products' => array(
        'Product 1' => '/products/1',
        'Product 2' => '/products/2',
        'Product 3' => '/products/3',
        'Nested Product' => array(
            'Nested 1' => '/products/nested/1',
            'Nested 2' => '/products/nested/2'
        )
    ),
    'Company' => '/company',
    'Privacy Policy' => '/privacy-policy'
);

class NavBuilder extends RecursiveIteratorIterator {

    // stores the previous depth
    private $_depth = 0;

    // stores the current iteration's depth
    private $_curDepth = 0;

    // store the iterator
    protected $_it;

    /**
     * Constructor.
     *
     * @access  public
     * @param   Traversable $it
     * @param   int         $mode
     * @param   int         $flags
     */
    public function __construct(Traversable $it, $mode = RecursiveIteratorIterator::SELF_FIRST, $flags = 0)
    {
        parent::__construct($it, $mode, $flags);

        // store the caching iterator
        $this->_it = $it;
    }

    /**
     * Override the return values.
     *
     * @access  public
     */
    public function current()
    {
        // the return output string
        $output = '';

        // set the current depth
        $this->_curDepth = parent::getDepth();

        // store the difference in depths
        $diff = abs($this->_curDepth - $this->_depth);

        // get the name and url of the nav item
        $name = parent::key();
        $url = parent::current();

        // close previous nested levels
        if ($this->_curDepth < $this->_depth) {
            $output .= str_repeat('</ul></li>', $diff);
        }

        // check if we have the last nav item
        if ($this->hasNext()) {
            $output .= '<li><a href="' . $url . '">' . $name . '</a>';
        } else {
            $output .= '<li class="last"><a href="' . $url . '">' . $name . '</a>';
        }

        // either add a subnav or close the list item
        if ($this->hasChildren()) {
            $output .= '<ul>';
        } else {
            $output .= '</li>';
        }

        // cache the depth
        $this->_depth = $this->_curDepth;

        // return the output ( we could've also overridden current())
        return $output;
    }

}
?>

使用

代码语言:javascript
运行
复制
<?php

try {

    // generate the recursive caching iterator
    $it = new RecursiveCachingIterator(new RecursiveArrayIterator($nav));

    // build the navigation with the iterator
    $it = new NavBuilder($it, RecursiveIteratorIterator::SELF_FIRST);

    // display the resulting navigation
    echo '<ul id="nav">' . PHP_EOL;
    foreach ($it as $value) {
        echo $value . "\n";
    }
    echo '</ul>' . PHP_EOL;

} catch (Exception $e) {
    var_dump($e); die;
}
?>
票数 3
EN

Stack Overflow用户

发布于 2012-02-28 09:30:55

你需要一个类迭代器来做这个吗?你只需要一个简单的函数就可以做到这一点。

代码语言:javascript
运行
复制
function arrayToListHTML($array, $level = 0) {
    static $tab = "\t";
    if (empty($array)) return;
    $tabs = str_repeat($tab, $level * 2);
    $result = "{$tabs}<ul>\n";
    foreach ($array as $i => $node):
        $result .= "{$tabs}{$tab}<li>\n{$tabs}{$tab}{$tab}{$node['title']}\n".arrayToListHTML($node['children'], $level + 1)."{$tabs}{$tab}</li>\n";
    endforeach;
    $result .= "{$tabs}</ul>\n";
    return $result;
}

这将产生以下输出:

代码语言:javascript
运行
复制
<ul>
    <li>
        NodeLvl1
    </li>
    <li>
        NodeLvl1
        <ul>
            <li>
                NodeLvl2
            </li>
            <li>
                NodeLvl2
                <ul>
                    <li>
                        NodeLvl3
                    </li>
                    <li>
                        NodeLvl3
                    </li>
                </ul>
            </li>
        </ul>
    </li>
    <li>
        NodeLvl1
    </li>
</ul>

这涵盖了您向我们展示的内容,但我不确定您所说的其他属性是什么意思。除了titlechildren之外,每个数组中是否还有其他属性

票数 15
EN

Stack Overflow用户

发布于 2012-03-07 21:12:40

不要试图像在foreach()中使用数组一样使用您的类,请考虑使用您的类来执行函数。例如,以下代码将正确输出,但函数是在类中执行的。

代码语言:javascript
运行
复制
class It extends RecursiveIteratorIterator{

  protected
    $tab    = "\t";

  public function beginChildren(){

    if(count($this->getInnerIterator()) == 0)
      return;
    echo str_repeat($this->tab, $this->getDepth())."<ul>\n";
  }

  public function endChildren(){


    if(count($this->getInnerIterator()) == 0)
      return;

    echo str_repeat($this->tab, $this->getDepth)."\n</ul>";
  }

  public function nextElement(){
    echo str_repeat($this->tab, $this->getDepth())."<li>".$this->current()."</li>\n";
  }

}

$it = new It(new RecursiveArrayIterator($nodes));
foreach($it as $key => $item)
  //echo $item;
  //it will be better to write a function inside your custom iterator class to handle iterations
?>
票数 4
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/9474944

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档