当前位置: 首页 > 知识库问答 >
问题:

递归foreach()在循环时产生重复结果

季俭
2023-03-14

这个类被设计来迭代WordPress菜单结构(嵌套数组/对象)以产生一个完成的菜单。虽然我的数据来源是WordPress,但我觉得这个问题属于SO而不是WP. SO,因为这个问题更植根于PHP(适用于任何试图递归的人)。

出于某种原因,我在层次结构中看到了重复的结果。另外,我注意到某些HTML元素没有正确关闭。看起来我已经正确地嵌套了所有内容,但结果就是您在这里看到的。

为了帮助调试,我添加了一些*,以直观地影响标记。也许你们知道一些我不知道的事情。祝你们好运,并提前感谢你们的投入!

我的班级

class Nav_Menu
{
    public $wp_nav;
    public $nested_nav;
    public $recursion_depth = 0;

    function __construct( $menu, $args = array() )
    {
        $format = new Format;

        if( $menu )
        {
            $this->wp_nav = wp_get_nav_menu_items($menu, $args);
            $this->nested_nav = $this->build_tree($this->wp_nav);

            $output = $this->build_output($this->nested_nav);
            $output_formatted = $format->HTML($output);

            // echo $output;
            echo $output_formatted;
        }
    }

    private function build_output( $menu = array() )
    {
        $output = '**';
        $output.= $this->recurse_menu($menu, $output);

        return $output;
    }

    private function recurse_menu( $menu = array(), $output )
    {
        global $post;

        if( !empty($menu) && !empty($output) )
        {
            $this->recursion_depth++;

            // ul classes
            $classes_ul = array();
            $classes_ul[] = ( $this->recursion_depth > 1 ? 'sub-menu' : '' );
            $classes_ul[] = 'depth-' . $this->recursion_depth;

            // process list wrappers
            $output.= '<ul class="' . $this->process_classes($classes_ul) . '">';

            // loop through menu items
            foreach( $menu as $menu_key => $menu_val )
            {
                // process list items
                $output.= '<li>' . $menu_val->title;

                // if necessary, handle children and recurse
                if( !empty($menu_val->children) )
                {
                    // recurse, and call this again
                    $output.= $this->recurse_menu($menu_val->children, $output);
                }

                // process list items
                $output.= '</li>';
            }

            // process list wrappers
            $output.= '</ul>';
        }

        return $output;
    }

    private function process_classes($classes = array())
    {
        if( !$classes )
        {
            return;
        }

        return trim(implode(' ', $classes));
    }

    private function build_tree( $elements = array(), $parent_id = 0 )
    {
        $branch = array();
        foreach($elements as $element)
        {
            if ($element->menu_item_parent == $parent_id)
            {
                $children = $this->build_tree($elements, $element->ID);
                if ($children)
                {
                    $element->children = $children;
                }

                $branch[] = $element;
            }
        }

        return $branch;
    }
}

$mynav = new Nav_Menu('Test Menu');

产生的输出

****
<ul class="depth-1">
    <li>
        One**
        <ul class="depth-1">
            <li>
                One
                <ul class="sub-menu depth-2">
                    <li>
                        Sub One
                    </li>
                    <li>
                        Sub Two
                    </li>
                    <li>
                        Sub Three
                    </li>
                </ul>
            </li>
            <li>
                Two
            </li>
            <li>
                Three**
                <ul class="depth-1">
                    <li>
                        One**
                        <ul class="depth-1">
                            <li>
                                One
                                <ul class="sub-menu depth-2">
                                    <li>
                                        Sub One
                                    </li>
                                    <li>
                                        Sub Two
                                    </li>
                                    <li>
                                        Sub Three
                                    </li>
                                </ul>
                            </li>
                            <li>
                                Two
                            </li>
                            <li>
                                Three
                                <ul class="sub-menu depth-3">
                                    <li>
                                        Sub One
                                    </li>
                                    <li>
                                        Sub Two
                                    </li>
                                </ul>
                            </li>
                            <li>
                                Four
                            </li>
                        </ul>

后端的WordPress菜单

共有2个答案

左丘修齐
2023-03-14

按如下所示更新生成输出方法:

private function build_output( $menu = array() )
{
    $output = '<ul>';
    $output = $this->recurse_menu($menu, $output);
    $output.= '</ul>';
    return $output;
}

更新递归菜单方法,如下所示:

private function recurse_menu( $menu = array(), $output = '')
{
     global $post;
     if( !empty($menu))
      {
        $this->recursion_depth++;
        // ul classes
        $classes_ul = array();
        $classes_ul[] = ( $this->recursion_depth > 1 ? 'sub-menu' : '' );
        $classes_ul[] = 'depth-' . $this->recursion_depth;

        // loop through menu items
        foreach( $menu as $menu_key => $menu_val )
        {
            // if necessary, handle children and recurse
            if( !empty($menu_val->children) )
            {
                // recurse, and call this again
                $output.= '<li><a href="#">'.$menu_val->title.'</a><ul class="' . $this->process_classes($classes_ul) . '">'.$this->recurse_menu($menu_val->children).'</ul></li>';

            }
            else {
            $output.= '<li><a href="#">'.$menu_val->title.'</a></li>';
            }

        }
    }

    return $output;
}

注意:我已经用更多的子级别测试了它,它工作正常。

奚和光
2023-03-14

如果有人知道原因,我愿意知道,所以我现在保留选择答案的权利。我猜是变量$output的某种奇怪的名称空间/范围问题。谁知道呢,我现在有点累了。

得到合法建筑的方法是...

class Nav_Menu
{
    public $wp_nav;
    public $nested_nav;
    public $recursion_depth = 0;
    public $output = '';

    function __construct( $menu, $args = array() )
    {
        $format = new Format;

        if( $menu )
        {
            $this->wp_nav = wp_get_nav_menu_items($menu, $args);
            $this->nested_nav = $this->build_tree($this->wp_nav);

            $this->build_output($this->nested_nav);
            $output_formatted = $format->HTML($this->output);

            // echo $this->output;
            echo $output_formatted;
        }
    }

    private function build_output( $menu = array() )
    {
        $this->recurse_menu($menu);
    }

    private function recurse_menu( $menu = array() )
    {
        global $post;

        if( !empty($menu) )
        {
            $this->recursion_depth++;

            // ul classes
            $classes_ul = array();
            $classes_ul[] = ( $this->recursion_depth > 1 ? 'sub-menu' : '' );
            $classes_ul[] = 'depth-' . $this->recursion_depth;

            // process list wrappers
            $this->output.= '<ul class="' . $this->process_classes($classes_ul) . '">';

            // loop through menu items
            foreach( $menu as $menu_key => $menu_val )
            {
                // process list items
                $this->output.= '<li>';
                $this->output.= $menu_val->title;

                // if necessary, handle children and recurse
                if( !empty($menu_val->children) )
                {
                    // recurse, and call this again
                    $this->recurse_menu($menu_val->children);
                }

                // process list items
                $this->output.= '</li>';
            }

            // process list wrappers
            $this->output.= '</ul>';
        }
    }

    private function process_classes($classes = array())
    {
        if( !$classes )
        {
            return;
        }

        return trim(implode(' ', $classes));
    }

    private function build_tree( $elements = array(), $parent_id = 0 )
    {
        $branch = array();
        foreach($elements as $element)
        {
            if ($element->menu_item_parent == $parent_id)
            {
                $children = $this->build_tree($elements, $element->ID);
                if ($children)
                {
                    $element->children = $children;
                }

                $branch[] = $element;
            }
        }

        return $branch;
    }
}

$mynav = new Nav_Menu('Test Menu'); exit;

结果输出

<ul class="depth-1">
    <li>
        One
        <ul class="sub-menu depth-2">
            <li>
                Sub One
            </li>
            <li>
                Sub Two
            </li>
            <li>
                Sub Three
            </li>
        </ul>
    </li>
    <li>
        Two
    </li>
    <li>
        Three
        <ul class="sub-menu depth-3">
            <li>
                Sub One
            </li>
            <li>
                Sub Two
            </li>
        </ul>
    </li>
    <li>
        Four
    </li>
</ul>

我只是为类创建了一个私有变量,每次我需要引用它作为存储位置时,我都只是追加到它。和以前一样,但是不再需要通过一些疯狂的方法链传递$out

如果有人有任何其他可以帮助社区的想法,请分享!

 类似资料:
  • 我有一个用户表和一个高尔夫比赛分数表。当用户参加比赛时,他使用表格在结果表中记录分数。我想显示一个结果表,显示用户的完整列表和比赛的分数。表中有八列分数——每门课一列。我正在努力使用php代码来显示结果分数。如果一名球员已经比赛,他的得分将正确显示,但如果表中的下一名球员没有比赛,则他的得分将显示为表中高于他的球员的得分。这将在列表中继续下去,直到获得真正的分数。我试图找到答案,但没有成功。这是我

  • 如何在javascript中递归循环json对象数据键。 请检查以下json对象:

  • 在js中,当在forEach函数中遍历arrayitems时,我遇到了一个问题。我只是有一个ID数组,其中一些ID不到10个字符,我想在开头用“0”填充这些字符。示例:在这种情况下,我想用填充最后一项。当然,它也可以在各种其他方式,但我只是不明白为什么它不起作用。 下面是我的代码:

  • foreach循环遍历列表值并将控制变量(var)依次设置为列表的每个元素 - 语法 (Syntax) Perl编程语言中foreach循环的语法是 - foreach var (list) { ... } 流程图 (Flow Diagram) 例子 (Example) #!/usr/local/bin/perl @list = (2, 20, 30, 40, 50); # foreach lo

  • 除了前面介绍的几种循环语句外,C# 同样也支持 foreach 循环,使用 foreach 可以遍历数组或者集合对象中的每一个元素,其语法格式如下: foreach(数据类型 变量名 in 数组或集合对象){     语句块; } foreach 会在每次循环的过程中,依次从数组或集合对象中取出一个新的元素放到 里定义的变量中,直到所有元素都成功取出后退出循环。 【示例】使用 foreach 循环

  • 本文向大家介绍C# Foreach循环,包括了C# Foreach循环的使用技巧和注意事项,需要的朋友参考一下 示例 foreach将迭代实现的类的任何对象IEnumerable(请注意IEnumerable<T>从其继承的对象)。此类对象包括一些内置对象,但不限于:List<T>,T[](任何类型的数组),Dictionary<TKey, TSource>以及诸如IQueryable和IColl