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>
我的导航菜单目前有两个 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>