PHP - foreach 循环的效率

PHP - efficiency of foreach loop

我的导航菜单目前有两个 foreach 循环;第一个将显示所有父导航链接,第二个显示子导航链接。

我正在寻找一种方法来将第二个 foreach 循环更改为仅循环遍历相关的子导航项,而不是检查每个父项的 each 导航。

解决此问题的最佳方法是什么?

代码:

<ul id="nav">
    <?php
    if($grabNav = $db->prepare("SELECT caption,url,visibility,id,class,parent_id FROM navigation ORDER BY parent_id ASC, order_id ASC"))
    {
        $grabNav->execute();
        $grabNav = $grabNav->fetchAll();
        foreach($grabNav as $nav)
        {
            $visibility = true;
            switch($nav['visibility'])
            {
                default:
                case 0: $visibility = false; break;
                case 1: $visibility = true; break;
                case 2: if(LOGGED_IN && isset($cUser)) { $visibility = true; } else { $visibility = false; } break;
                case 3: if(LOGGED_IN && isset($cUser)) { $visibility = false; } else { $visibility = true; } break;
            }
            if(!$visibility) { continue; }
            if($nav['parent_id'] != -1) { continue; }

            $class = $core->output($nav['class']);
            if($nav['id'] == PAGE_ID) { $class .= ' selected'; }
            echo '<li class="'.$class.'"><a href="'.$core->output($nav['url']).'">'.$core->output($nav['caption'],true).'</a><ul id="subNav">';
            foreach($grabNav as $sub)
            {
                if($sub['parent_id'] == $nav['id'])
                {
                    $visibility = true;
                    switch($sub['visibility'])
                    {
                        default:
                        case 0: $visibility = false; break;
                        case 1: $visibility = true; break;
                        case 2: if(LOGGED_IN && isset($cUser)) { $visibility = true; } else { $visibility = false; } break;
                        case 3: if(LOGGED_IN && isset($cUser)) { $visibility = false; } else { $visibility = true; } break;
                    }
                    if(!$visibility) { continue; }
                    $subClass = $core->output($sub['class']);
                    echo'<li class="'.$subClass.'"><a href="'.$core->output($sub['url']).'">'.$core->output($sub['caption'],true).'</a></li>';
                }
            }
            echo'</ul></li>';
        }
    }
    ?>
</ul>

在您的初始查询 db->prepare("SELECT caption,url,visibility,id,class,parent_id FROM navigation ORDER BY parent_id ASC, order_id ASC")) 中,您可以 JOIN 使用相同的 table ON navigation.parent_id=id

您将需要枚举您选择的字段以避免 'more than one found' SQL 错误,例如 SELECT orig.caption AS caption FROM navigation JOIN navigation ON parent_id=id。注意 orig.caption AS caption 位!

@Bing 的答案是更好的解决方案,但如果您不喜欢 sql 这样做,您也可以创建新的树数组,其中根是父级元素,但在下一个级别 - 儿童。您将在可视化之前进行一次,然后再进行一次可视化。 如果不清楚 - 告诉我,我会向您展示预通过的示例代码。

希望下面的示例对您有所帮助:)

<?php
// SAMPLE DATA
$grabNav=array(
    0=>array('id'=>1,'parent_id'=>-1,'caption'=>'main-1'),
    1=>array('id'=>3,'parent_id'=>1,'caption'=>'sub 1-1'),
    2=>array('id'=>5,'parent_id'=>1,'caption'=>'sub 1-2'),
    3=>array('id'=>7,'parent_id'=>2,'caption'=>'sub 2-1'),
    4=>array('id'=>6,'parent_id'=>4,'caption'=>'sub 3-1'),
    5=>array('id'=>2,'parent_id'=>-1,'caption'=>'home-2'),
    6=>array('id'=>4,'parent_id'=>-1,'caption'=>'home-3'),
    7=>array('id'=>8,'parent_id'=>-1,'caption'=>'home-4'),
);

$new_array=array();
// PRE - PASS to organize the results in the new tree-array
foreach($grabNav as $nav){
    if($nav['parent_id']!=-1){ // children
        if(!isset($new_array[$nav['parent_id']])){
            $new_array[$nav['parent_id']]=array(
                'data'=>array(),
                'sub'=>array(),
            );
        }
        $new_array[$nav['parent_id']]['sub'][$nav['id']]=$nav;
    }
    else { // parent
        if(!isset($new_array[$nav['id']])){
            $new_array[$nav['id']]=array(
                'data'=>array(),
                'sub'=>array(),
            );
        }
        $new_array[$nav['id']]['data']=$nav;
    }
}
// VISUALIZATION
foreach($new_array as $root){
    echo $root['data']['caption']."<br/>"; 
    foreach($root['sub'] as $branch){
        echo "--- ".$branch['caption']."<br/>"; 
    }
}
?>
<pre><?= print_r($new_array) ?></pre>