如何更新使用已弃用的 each() 的代码
How to update code that uses deprecated each()
我正在尝试更新一段旧代码(菜单生成器 class)。我已经更新了所有其他内容,但我被困在使用 each() 函数的行。我确实阅读了之前的一些主题,但这个特定实例太复杂了,我无法弄清楚如何更改。这是:
while ( $loop && ( ( $option = each( $children[$parent] ) ) || ( $parent > $root_id ) ) )
这是出现上述行的整个函数:
function get_menu_html($lang, $root_id = 0 )
{
$this->html = array();
$this->items = $this->get_menu_items($lang);
foreach ( $this->items as $item )
$children[$item['sectionParentID']][] = $item;
// loop will be false if the root has no children (i.e., an empty menu!)
$loop = !empty( $children[$root_id] );
// initializing $parent as the root
$parent = $root_id;
$parent_stack = array();
// HTML wrapper for the menu (open)
$this->html[] = '<ul>';
while ( $loop && ( ( $option = each( $children[$parent] ) ) || ( $parent > $root_id ) ) )
{
if ( $option === false )
{
$parent = array_pop( $parent_stack );
// HTML for menu item containing children (close)
$this->html[] = str_repeat( "\t", ( count( $parent_stack ) + 1 ) * 2 ) . '</ul>';
$this->html[] = str_repeat( "\t", ( count( $parent_stack ) + 1 ) * 2 - 1 ) . '</li>';
}
elseif ( !empty( $children[$option['value']['sectionID']] ) )
{
$tab = str_repeat( "\t", ( count( $parent_stack ) + 1 ) * 2 - 1 );
// HTML for menu item containing children (open)
$this->html[] = sprintf(
'%1$s<li><a href="%2$s">%3$s</a>',
$tab, // %1$s = tabulation
$option['value']['sectionPage'], // %2$s = sectionPage (URL)
$option['value']['sectionLabel'] // %3$s = title
);
$this->html[] = $tab . "\t" . '<ul class="submenu">';
array_push( $parent_stack, $option['value']['sectionParentID'] );
$parent = $option['value']['sectionID'];
}
else
// HTML for menu item with no children (aka "leaf")
$this->html[] = sprintf(
'%1$s<li><a href="%2$s">%3$s</a></li>',
str_repeat( "\t", ( count( $parent_stack ) + 1 ) * 2 - 1 ), // %1$s = tabulation
$option['value']['sectionPage'], // %2$s = sectionPage (URL)
$option['value']['sectionLabel'] // %3$s = title
);
}
编辑:添加屏幕截图以显示这段代码和下面的两个建议产生的结果。
原始(使用已弃用的 each() 函数):
乔希的版本:
凯文 Y 的版本:
编辑 2:如果您想用我自己的数据进行测试,这是我使用 get_menu_items($lang)
从我的数据库中获得的打印结果:
Array ( [0] => Array ( [sectionID] => 1 [sectionParentID] => 0 [sectionPage] => Home [sectionLabel] => Начало ) [1] => Array ( [sectionID] => 2 [sectionParentID] => 0 [sectionPage] => Translations [sectionLabel] => Преvоди ) [2] => Array ( [sectionID] => 3 [sectionParentID] => 0 [sectionPage] => Prose [sectionLabel] => Проzа ) [3] => Array ( [sectionID] => 4 [sectionParentID] => 0 [sectionPage] => Poetry [sectionLabel] => Поезiя ) [4] => Array ( [sectionID] => 5 [sectionParentID] => 3 [sectionPage] => Stories [sectionLabel] => Разкази ) [5] => Array ( [sectionID] => 6 [sectionParentID] => 3 [sectionPage] => Articles [sectionLabel] => Статии ) [6] => Array ( [sectionID] => 7 [sectionParentID] => 3 [sectionPage] => Essays [sectionLabel] => Есета ) [7] => Array ( [sectionID] => 8 [sectionParentID] => 3 [sectionPage] => Fragments [sectionLabel] => Фрагменти ) [8] => Array ( [sectionID] => 9 [sectionParentID] => 4 [sectionPage] => Woman [sectionLabel] => Аз и Жената ) [9] => Array ( [sectionID] => 10 [sectionParentID] => 4 [sectionPage] => Civilization [sectionLabel] => Аз и Цивилизацията ) [10] => Array ( [sectionID] => 11 [sectionParentID] => 4 [sectionPage] => Universe [sectionLabel] => Аз и Вселената ) [11] => Array ( [sectionID] => 12 [sectionParentID] => 4 [sectionPage] => Duskoreznitsa [sectionLabel] => (По-)Етична дъскорезница ) [12] => Array ( [sectionID] => 13 [sectionParentID] => 4 [sectionPage] => PrazniPrikazki [sectionLabel] => Празни приказки ) [13] => Array ( [sectionID] => 14 [sectionParentID] => 4 [sectionPage] => Extrakts [sectionLabel] => Екстракти ) [14] => Array ( [sectionID] => 17 [sectionParentID] => 0 [sectionPage] => Blog [sectionLabel] => Трънки и блогинkи ) [15] => Array ( [sectionID] => 18 [sectionParentID] => 0 [sectionPage] => Contact [sectionLabel] => Контакт ) [16] => Array ( [sectionID] => 19 [sectionParentID] => 0 [sectionPage] => About [sectionLabel] => За сайта ) [17] => Array ( [sectionID] => 20 [sectionParentID] => 3 [sectionPage] => Research [sectionLabel] => Изследвания ) [18] => Array ( [sectionID] => 21 [sectionParentID] => 3 [sectionPage] => Amsterdamned [sectionLabel] => Amsterdamned ) [19] => Array ( [sectionID] => 22 [sectionParentID] => 4 [sectionPage] => Treski [sectionLabel] => Трески ) [20] => Array ( [sectionID] => 23 [sectionParentID] => 2 [sectionPage] => PoetryTranslation [sectionLabel] => Преводи на поезия ) [21] => Array ( [sectionID] => 25 [sectionParentID] => 2 [sectionPage] => ProseTranslation [sectionLabel] => Преводи на проза ) [22] => Array ( [sectionID] => 27 [sectionParentID] => 2 [sectionPage] => SubtitleTranslation [sectionLabel] => Преводи на субтитри ) [23] => Array ( [sectionID] => 28 [sectionParentID] => 2 [sectionPage] => OpinionJournalismTranslation [sectionLabel] => Преводи на публицистика ) )
parent_id
替换为 sectionParentID
id
替换为 sectionID
link
替换为 sectionPage
title
替换为 sectionLabel
。
作为一般规则,如果您需要离开 each($ar)
,您通常可以使用 [key($ar),current($ar)]
作为替代品,但您需要在循环内移动指针。您通常只需要在循环中调用 next($ar)
并在 运行 离开阅览室后中断,例如当键为空时中断。然后确保数组在 运行 空间不足时设置为 false。
由于额外的代码,这种方法很快就会变得丑陋...
所以没有真正关注你的代码,在这次更新之后,你修改后的代码看起来像:
function get_menu_html($lang, $root_id = 0 )
{
$this->html = array();
$this->items = $this->get_menu_items($lang);
foreach ( $this->items as $item )
$children[$item['sectionParentID']][] = $item;
// loop will be false if the root has no children (i.e., an empty menu!)
$loop = !empty( $children[$root_id] );
// initializing $parent as the root
$parent = $root_id;
$parent_stack = array();
// HTML wrapper for the menu (open)
$this->html[] = '<ul>';
while ( $loop && ( ( $option = [key($children[$parent]),current($children[$parent])] ) || ( $parent > $root_id ) ) )
{
if($option[0] === null){$option = false;} // replicate each's behavior for after last element
next($children[$parent]);
if ( $option === false )
{
$parent = array_pop( $parent_stack );
// HTML for menu item containing children (close)
$this->html[] = str_repeat( "\t", ( count( $parent_stack ) + 1 ) * 2 ) . '</ul>';
$this->html[] = str_repeat( "\t", ( count( $parent_stack ) + 1 ) * 2 - 1 ) . '</li>';
break;
}
elseif ( !empty( $children[$option['value']['sectionID']] ) )
{
$tab = str_repeat( "\t", ( count( $parent_stack ) + 1 ) * 2 - 1 );
// HTML for menu item containing children (open)
$this->html[] = sprintf(
'%1$s<li><a href="%2$s">%3$s</a>',
$tab, // %1$s = tabulation
$option['value']['sectionPage'], // %2$s = sectionPage (URL)
$option['value']['sectionLabel'] // %3$s = title
);
$this->html[] = $tab . "\t" . '<ul class="submenu">';
array_push( $parent_stack, $option['value']['sectionParentID'] );
$parent = $option['value']['sectionID'];
}
else
// HTML for menu item with no children (aka "leaf")
$this->html[] = sprintf(
'%1$s<li><a href="%2$s">%3$s</a></li>',
str_repeat( "\t", ( count( $parent_stack ) + 1 ) * 2 - 1 ), // %1$s = tabulation
$option['value']['sectionPage'], // %2$s = sectionPage (URL)
$option['value']['sectionLabel'] // %3$s = title
);
}
编辑:请注意上面的代码不起作用,因为它从每个引用 $option['value']
而不是从每个引用 $option[1]
。需要在代码中进行调整。
您可能还想重构代码。但是,在没有弃用代码的情况下让它正常工作,是很好的第一步。
虽然这种方法通常非常难看。最好重构并使用某种特定于代码逻辑的 foreach 循环。
编辑:
这是我正在从提供给原始代码的 中处理的一个孤立示例:
<?php
/**
* Generate HTML for multi-dimensional menu from MySQL database
* with ONE QUERY and WITHOUT RECURSION
* @author J. Bruni
*/
class MenuBuilder
{
/**
* Menu items
*/
var $items = array();
/**
* HTML contents
*/
var $html = array();
/**
* Get all menu items from database
*/
function get_menu_items()
{
// Change the field names and the table name in the query below to match tour needs
return [
['id'=>1, 'parent_id'=>0, 'title'=>'title 1','link'=>'link 1','position'=>'0'],
['id'=>2, 'parent_id'=>1, 'title'=>'title 2','link'=>'link 2','position'=>'0'],
['id'=>3, 'parent_id'=>1, 'title'=>'title 3','link'=>'link 3','position'=>'0'],
['id'=>4, 'parent_id'=>0, 'title'=>'title 4','link'=>'link 4','position'=>'0'],
];
}
/**
* Build the HTML for the menu
*/
function get_menu_html( $root_id = 0 )
{
$this->html = array();
$this->items = $this->get_menu_items();
foreach ( $this->items as $item )
$children[$item['parent_id']][] = $item;
// loop will be false if the root has no children (i.e., an empty menu!)
$loop = !empty( $children[$root_id] );
// initializing $parent as the root
$parent = $root_id;
$parent_stack = array();
// HTML wrapper for the menu (open)
$this->html[] = '<ul>';
while ( $loop && ( ( $option = each( $children[$parent] ) ) || ( $parent > $root_id ) ) )
{
if ( $option === false )
{
$parent = array_pop( $parent_stack );
// HTML for menu item containing childrens (close)
$this->html[] = str_repeat( "\t", ( count( $parent_stack ) + 1 ) * 2 ) . '</ul>';
$this->html[] = str_repeat( "\t", ( count( $parent_stack ) + 1 ) * 2 - 1 ) . '</li>';
}
elseif ( !empty( $children[$option['value']['id']] ) )
{
$tab = str_repeat( "\t", ( count( $parent_stack ) + 1 ) * 2 - 1 );
// HTML for menu item containing childrens (open)
$this->html[] = sprintf(
'%1$s<li><a href="%2$s">%3$s</a>',
$tab, // %1$s = tabulation
$option['value']['link'], // %2$s = link (URL)
$option['value']['title'] // %3$s = title
);
$this->html[] = $tab . "\t" . '<ul class="submenu">';
array_push( $parent_stack, $option['value']['parent_id'] );
$parent = $option['value']['id'];
}
else
// HTML for menu item with no children (aka "leaf")
$this->html[] = sprintf(
'%1$s<li><a href="%2$s">%3$s</a></li>',
str_repeat( "\t", ( count( $parent_stack ) + 1 ) * 2 - 1 ), // %1$s = tabulation
$option['value']['link'], // %2$s = link (URL)
$option['value']['title'] // %3$s = title
);
}
// HTML wrapper for the menu (close)
$this->html[] = '</ul>';
return implode( "\r\n", $this->html );
}
}
$menu = new MenuBuilder();
echo '<pre>' . $menu->get_menu_html() . '</pre>';
?>
里面仍然有“each”,但是它是独立的,所以应该更容易转换。
可以在这里玩:https://sandbox.onlinephpfunctions.com/
现在正在努力进行转换...
这是我写的 drop-in 替换:
public function each(&$ar)
{
$key = key($ar);
if($key === null){return false;}
$current = current($ar);
try
{
return [$key,$current,'key'=>$key,'value'=>$current];
}finally{
next($ar);
};
}
然后代替:
while ( $loop && ( ( $option = each( $children[$parent] ) ) || ( $parent > $root_id ) ) )
使用:
while ( $loop && ( ( $option = $this->each( $children[$parent] ) ) || ( $parent > $root_id ) ) )
即使用 $this->each 而不是 each.
最终代码:
<?php
/**
* Generate HTML for multi-dimensional menu from MySQL database
* with ONE QUERY and WITHOUT RECURSION
* @author J. Bruni
*/
class MenuBuilder
{
/**
* Menu items
*/
var $items = array();
/**
* HTML contents
*/
var $html = array();
public function each(&$ar)
{
$key = key($ar);
if($key === null){return false;}
$current = current($ar);
try
{
return [$key,$current,'key'=>$key,'value'=>$current];
}finally{
next($ar);
};
}
/**
* Get all menu items from database
*/
function get_menu_items()
{
// Change the field names and the table name in the query below to match tour needs
return [
['id'=>1, 'parent_id'=>0, 'title'=>'title 1','link'=>'link 1','position'=>'0'],
['id'=>2, 'parent_id'=>1, 'title'=>'title 2','link'=>'link 2','position'=>'0'],
['id'=>3, 'parent_id'=>1, 'title'=>'title 3','link'=>'link 3','position'=>'0'],
['id'=>4, 'parent_id'=>0, 'title'=>'title 4','link'=>'link 4','position'=>'0'],
];
}
/**
* Build the HTML for the menu
*/
function get_menu_html( $root_id = 0 )
{
$this->html = array();
$this->items = $this->get_menu_items();
foreach ( $this->items as $item )
$children[$item['parent_id']][] = $item;
// loop will be false if the root has no children (i.e., an empty menu!)
$loop = !empty( $children[$root_id] );
// initializing $parent as the root
$parent = $root_id;
$parent_stack = array();
// HTML wrapper for the menu (open)
$this->html[] = '<ul>';
while ( $loop && ( ( $option = $this->each( $children[$parent] ) ) || ( $parent > $root_id ) ) )
{
if ( $option === false )
{
$parent = array_pop( $parent_stack );
// HTML for menu item containing childrens (close)
$this->html[] = str_repeat( "\t", ( count( $parent_stack ) + 1 ) * 2 ) . '</ul>';
$this->html[] = str_repeat( "\t", ( count( $parent_stack ) + 1 ) * 2 - 1 ) . '</li>';
}
elseif ( !empty( $children[$option['value']['id']] ) )
{
$tab = str_repeat( "\t", ( count( $parent_stack ) + 1 ) * 2 - 1 );
// HTML for menu item containing childrens (open)
$this->html[] = sprintf(
'%1$s<li><a href="%2$s">%3$s</a>',
$tab, // %1$s = tabulation
$option['value']['link'], // %2$s = link (URL)
$option['value']['title'] // %3$s = title
);
$this->html[] = $tab . "\t" . '<ul class="submenu">';
array_push( $parent_stack, $option['value']['parent_id'] );
$parent = $option['value']['id'];
}
else
// HTML for menu item with no children (aka "leaf")
$this->html[] = sprintf(
'%1$s<li><a href="%2$s">%3$s</a></li>',
str_repeat( "\t", ( count( $parent_stack ) + 1 ) * 2 - 1 ), // %1$s = tabulation
$option['value']['link'], // %2$s = link (URL)
$option['value']['title'] // %3$s = title
);
}
// HTML wrapper for the menu (close)
$this->html[] = '</ul>';
return implode( "\r\n", $this->html );
}
}
$menu = new MenuBuilder();
echo '<pre>' . $menu->get_menu_html() . '</pre>';
?>
我从检查第三个 while 循环条件开始进行 foreach。
$this->html = array();
$this->items = $this->get_menu_items();
foreach ($this->items as $item)
$children[$item['parent_id']][] = $item;
// loop will be false if the root has no children (i.e., an empty menu!)
$loop = !empty($children[$root_id]);
// initializing $parent as the root
$parent = $root_id;
$parent_stack = array();
// HTML wrapper for the menu (open)
$this->html[] = '<ul>';
if ($loop) {
foreach ($children[$parent] as $option) {
if ($parent > $root_id) {
break; // exit loop
}
if ($option === false) {
$parent = array_pop($parent_stack);
// HTML for menu item containing childrens (close)
$this->html[] = str_repeat("\t", (count($parent_stack) + 1) * 2) . '</ul>';
$this->html[] = str_repeat("\t", (count($parent_stack) + 1) * 2 - 1) . '</li>';
} elseif (!empty($children[$option['id']])) {
$tab = str_repeat("\t", (count($parent_stack) + 1) * 2 - 1);
// HTML for menu item containing childrens (open)
$this->html[] = sprintf(
'%1$s<li><a href="%2$s">%3$s</a>',
$tab, // %1$s = tabulation
$option['link'], // %2$s = link (URL)
$option['title'] // %3$s = title
);
$this->html[] = $tab . "\t" . '<ul class="submenu">';
array_push($parent_stack, $option['parent_id']);
$parent = $option['id'];
} else
// HTML for menu item with no children (aka "leaf")
$this->html[] = sprintf(
'%1$s<li><a href="%2$s">%3$s</a></li>',
str_repeat("\t", (count($parent_stack) + 1) * 2 - 1), // %1$s = tabulation
$option['link'], // %2$s = link (URL)
$option['title'] // %3$s = title
);
}
// HTML wrapper for the menu (close)
$this->html[] = '</ul>';
return implode("\r\n", $this->html);
}
测试:
[
['id'=>1, 'parent_id'=>0, 'title'=>'title 1','link'=>'link 1','position'=>'0'],
['id'=>2, 'parent_id'=>1, 'title'=>'title 2','link'=>'link 2','position'=>'0'],
['id'=>3, 'parent_id'=>1, 'title'=>'title 3','link'=>'link 3','position'=>'0'],
['id'=>4, 'parent_id'=>0, 'title'=>'title 4','link'=>'link 4','position'=>'0'],
];
我正在尝试更新一段旧代码(菜单生成器 class)。我已经更新了所有其他内容,但我被困在使用 each() 函数的行。我确实阅读了之前的一些主题,但这个特定实例太复杂了,我无法弄清楚如何更改。这是:
while ( $loop && ( ( $option = each( $children[$parent] ) ) || ( $parent > $root_id ) ) )
这是出现上述行的整个函数:
function get_menu_html($lang, $root_id = 0 )
{
$this->html = array();
$this->items = $this->get_menu_items($lang);
foreach ( $this->items as $item )
$children[$item['sectionParentID']][] = $item;
// loop will be false if the root has no children (i.e., an empty menu!)
$loop = !empty( $children[$root_id] );
// initializing $parent as the root
$parent = $root_id;
$parent_stack = array();
// HTML wrapper for the menu (open)
$this->html[] = '<ul>';
while ( $loop && ( ( $option = each( $children[$parent] ) ) || ( $parent > $root_id ) ) )
{
if ( $option === false )
{
$parent = array_pop( $parent_stack );
// HTML for menu item containing children (close)
$this->html[] = str_repeat( "\t", ( count( $parent_stack ) + 1 ) * 2 ) . '</ul>';
$this->html[] = str_repeat( "\t", ( count( $parent_stack ) + 1 ) * 2 - 1 ) . '</li>';
}
elseif ( !empty( $children[$option['value']['sectionID']] ) )
{
$tab = str_repeat( "\t", ( count( $parent_stack ) + 1 ) * 2 - 1 );
// HTML for menu item containing children (open)
$this->html[] = sprintf(
'%1$s<li><a href="%2$s">%3$s</a>',
$tab, // %1$s = tabulation
$option['value']['sectionPage'], // %2$s = sectionPage (URL)
$option['value']['sectionLabel'] // %3$s = title
);
$this->html[] = $tab . "\t" . '<ul class="submenu">';
array_push( $parent_stack, $option['value']['sectionParentID'] );
$parent = $option['value']['sectionID'];
}
else
// HTML for menu item with no children (aka "leaf")
$this->html[] = sprintf(
'%1$s<li><a href="%2$s">%3$s</a></li>',
str_repeat( "\t", ( count( $parent_stack ) + 1 ) * 2 - 1 ), // %1$s = tabulation
$option['value']['sectionPage'], // %2$s = sectionPage (URL)
$option['value']['sectionLabel'] // %3$s = title
);
}
编辑:添加屏幕截图以显示这段代码和下面的两个建议产生的结果。
原始(使用已弃用的 each() 函数):
乔希的版本:
凯文 Y 的版本:
编辑 2:如果您想用我自己的数据进行测试,这是我使用 get_menu_items($lang)
从我的数据库中获得的打印结果:
Array ( [0] => Array ( [sectionID] => 1 [sectionParentID] => 0 [sectionPage] => Home [sectionLabel] => Начало ) [1] => Array ( [sectionID] => 2 [sectionParentID] => 0 [sectionPage] => Translations [sectionLabel] => Преvоди ) [2] => Array ( [sectionID] => 3 [sectionParentID] => 0 [sectionPage] => Prose [sectionLabel] => Проzа ) [3] => Array ( [sectionID] => 4 [sectionParentID] => 0 [sectionPage] => Poetry [sectionLabel] => Поезiя ) [4] => Array ( [sectionID] => 5 [sectionParentID] => 3 [sectionPage] => Stories [sectionLabel] => Разкази ) [5] => Array ( [sectionID] => 6 [sectionParentID] => 3 [sectionPage] => Articles [sectionLabel] => Статии ) [6] => Array ( [sectionID] => 7 [sectionParentID] => 3 [sectionPage] => Essays [sectionLabel] => Есета ) [7] => Array ( [sectionID] => 8 [sectionParentID] => 3 [sectionPage] => Fragments [sectionLabel] => Фрагменти ) [8] => Array ( [sectionID] => 9 [sectionParentID] => 4 [sectionPage] => Woman [sectionLabel] => Аз и Жената ) [9] => Array ( [sectionID] => 10 [sectionParentID] => 4 [sectionPage] => Civilization [sectionLabel] => Аз и Цивилизацията ) [10] => Array ( [sectionID] => 11 [sectionParentID] => 4 [sectionPage] => Universe [sectionLabel] => Аз и Вселената ) [11] => Array ( [sectionID] => 12 [sectionParentID] => 4 [sectionPage] => Duskoreznitsa [sectionLabel] => (По-)Етична дъскорезница ) [12] => Array ( [sectionID] => 13 [sectionParentID] => 4 [sectionPage] => PrazniPrikazki [sectionLabel] => Празни приказки ) [13] => Array ( [sectionID] => 14 [sectionParentID] => 4 [sectionPage] => Extrakts [sectionLabel] => Екстракти ) [14] => Array ( [sectionID] => 17 [sectionParentID] => 0 [sectionPage] => Blog [sectionLabel] => Трънки и блогинkи ) [15] => Array ( [sectionID] => 18 [sectionParentID] => 0 [sectionPage] => Contact [sectionLabel] => Контакт ) [16] => Array ( [sectionID] => 19 [sectionParentID] => 0 [sectionPage] => About [sectionLabel] => За сайта ) [17] => Array ( [sectionID] => 20 [sectionParentID] => 3 [sectionPage] => Research [sectionLabel] => Изследвания ) [18] => Array ( [sectionID] => 21 [sectionParentID] => 3 [sectionPage] => Amsterdamned [sectionLabel] => Amsterdamned ) [19] => Array ( [sectionID] => 22 [sectionParentID] => 4 [sectionPage] => Treski [sectionLabel] => Трески ) [20] => Array ( [sectionID] => 23 [sectionParentID] => 2 [sectionPage] => PoetryTranslation [sectionLabel] => Преводи на поезия ) [21] => Array ( [sectionID] => 25 [sectionParentID] => 2 [sectionPage] => ProseTranslation [sectionLabel] => Преводи на проза ) [22] => Array ( [sectionID] => 27 [sectionParentID] => 2 [sectionPage] => SubtitleTranslation [sectionLabel] => Преводи на субтитри ) [23] => Array ( [sectionID] => 28 [sectionParentID] => 2 [sectionPage] => OpinionJournalismTranslation [sectionLabel] => Преводи на публицистика ) )
parent_id
替换为 sectionParentID
id
替换为 sectionID
link
替换为 sectionPage
title
替换为 sectionLabel
。
作为一般规则,如果您需要离开 each($ar)
,您通常可以使用 [key($ar),current($ar)]
作为替代品,但您需要在循环内移动指针。您通常只需要在循环中调用 next($ar)
并在 运行 离开阅览室后中断,例如当键为空时中断。然后确保数组在 运行 空间不足时设置为 false。
由于额外的代码,这种方法很快就会变得丑陋...
所以没有真正关注你的代码,在这次更新之后,你修改后的代码看起来像:
function get_menu_html($lang, $root_id = 0 )
{
$this->html = array();
$this->items = $this->get_menu_items($lang);
foreach ( $this->items as $item )
$children[$item['sectionParentID']][] = $item;
// loop will be false if the root has no children (i.e., an empty menu!)
$loop = !empty( $children[$root_id] );
// initializing $parent as the root
$parent = $root_id;
$parent_stack = array();
// HTML wrapper for the menu (open)
$this->html[] = '<ul>';
while ( $loop && ( ( $option = [key($children[$parent]),current($children[$parent])] ) || ( $parent > $root_id ) ) )
{
if($option[0] === null){$option = false;} // replicate each's behavior for after last element
next($children[$parent]);
if ( $option === false )
{
$parent = array_pop( $parent_stack );
// HTML for menu item containing children (close)
$this->html[] = str_repeat( "\t", ( count( $parent_stack ) + 1 ) * 2 ) . '</ul>';
$this->html[] = str_repeat( "\t", ( count( $parent_stack ) + 1 ) * 2 - 1 ) . '</li>';
break;
}
elseif ( !empty( $children[$option['value']['sectionID']] ) )
{
$tab = str_repeat( "\t", ( count( $parent_stack ) + 1 ) * 2 - 1 );
// HTML for menu item containing children (open)
$this->html[] = sprintf(
'%1$s<li><a href="%2$s">%3$s</a>',
$tab, // %1$s = tabulation
$option['value']['sectionPage'], // %2$s = sectionPage (URL)
$option['value']['sectionLabel'] // %3$s = title
);
$this->html[] = $tab . "\t" . '<ul class="submenu">';
array_push( $parent_stack, $option['value']['sectionParentID'] );
$parent = $option['value']['sectionID'];
}
else
// HTML for menu item with no children (aka "leaf")
$this->html[] = sprintf(
'%1$s<li><a href="%2$s">%3$s</a></li>',
str_repeat( "\t", ( count( $parent_stack ) + 1 ) * 2 - 1 ), // %1$s = tabulation
$option['value']['sectionPage'], // %2$s = sectionPage (URL)
$option['value']['sectionLabel'] // %3$s = title
);
}
编辑:请注意上面的代码不起作用,因为它从每个引用 $option['value']
而不是从每个引用 $option[1]
。需要在代码中进行调整。
您可能还想重构代码。但是,在没有弃用代码的情况下让它正常工作,是很好的第一步。
虽然这种方法通常非常难看。最好重构并使用某种特定于代码逻辑的 foreach 循环。
编辑:
这是我正在从提供给原始代码的
<?php
/**
* Generate HTML for multi-dimensional menu from MySQL database
* with ONE QUERY and WITHOUT RECURSION
* @author J. Bruni
*/
class MenuBuilder
{
/**
* Menu items
*/
var $items = array();
/**
* HTML contents
*/
var $html = array();
/**
* Get all menu items from database
*/
function get_menu_items()
{
// Change the field names and the table name in the query below to match tour needs
return [
['id'=>1, 'parent_id'=>0, 'title'=>'title 1','link'=>'link 1','position'=>'0'],
['id'=>2, 'parent_id'=>1, 'title'=>'title 2','link'=>'link 2','position'=>'0'],
['id'=>3, 'parent_id'=>1, 'title'=>'title 3','link'=>'link 3','position'=>'0'],
['id'=>4, 'parent_id'=>0, 'title'=>'title 4','link'=>'link 4','position'=>'0'],
];
}
/**
* Build the HTML for the menu
*/
function get_menu_html( $root_id = 0 )
{
$this->html = array();
$this->items = $this->get_menu_items();
foreach ( $this->items as $item )
$children[$item['parent_id']][] = $item;
// loop will be false if the root has no children (i.e., an empty menu!)
$loop = !empty( $children[$root_id] );
// initializing $parent as the root
$parent = $root_id;
$parent_stack = array();
// HTML wrapper for the menu (open)
$this->html[] = '<ul>';
while ( $loop && ( ( $option = each( $children[$parent] ) ) || ( $parent > $root_id ) ) )
{
if ( $option === false )
{
$parent = array_pop( $parent_stack );
// HTML for menu item containing childrens (close)
$this->html[] = str_repeat( "\t", ( count( $parent_stack ) + 1 ) * 2 ) . '</ul>';
$this->html[] = str_repeat( "\t", ( count( $parent_stack ) + 1 ) * 2 - 1 ) . '</li>';
}
elseif ( !empty( $children[$option['value']['id']] ) )
{
$tab = str_repeat( "\t", ( count( $parent_stack ) + 1 ) * 2 - 1 );
// HTML for menu item containing childrens (open)
$this->html[] = sprintf(
'%1$s<li><a href="%2$s">%3$s</a>',
$tab, // %1$s = tabulation
$option['value']['link'], // %2$s = link (URL)
$option['value']['title'] // %3$s = title
);
$this->html[] = $tab . "\t" . '<ul class="submenu">';
array_push( $parent_stack, $option['value']['parent_id'] );
$parent = $option['value']['id'];
}
else
// HTML for menu item with no children (aka "leaf")
$this->html[] = sprintf(
'%1$s<li><a href="%2$s">%3$s</a></li>',
str_repeat( "\t", ( count( $parent_stack ) + 1 ) * 2 - 1 ), // %1$s = tabulation
$option['value']['link'], // %2$s = link (URL)
$option['value']['title'] // %3$s = title
);
}
// HTML wrapper for the menu (close)
$this->html[] = '</ul>';
return implode( "\r\n", $this->html );
}
}
$menu = new MenuBuilder();
echo '<pre>' . $menu->get_menu_html() . '</pre>';
?>
里面仍然有“each”,但是它是独立的,所以应该更容易转换。 可以在这里玩:https://sandbox.onlinephpfunctions.com/
现在正在努力进行转换...
这是我写的 drop-in 替换:
public function each(&$ar)
{
$key = key($ar);
if($key === null){return false;}
$current = current($ar);
try
{
return [$key,$current,'key'=>$key,'value'=>$current];
}finally{
next($ar);
};
}
然后代替:
while ( $loop && ( ( $option = each( $children[$parent] ) ) || ( $parent > $root_id ) ) )
使用:
while ( $loop && ( ( $option = $this->each( $children[$parent] ) ) || ( $parent > $root_id ) ) )
即使用 $this->each 而不是 each.
最终代码:
<?php
/**
* Generate HTML for multi-dimensional menu from MySQL database
* with ONE QUERY and WITHOUT RECURSION
* @author J. Bruni
*/
class MenuBuilder
{
/**
* Menu items
*/
var $items = array();
/**
* HTML contents
*/
var $html = array();
public function each(&$ar)
{
$key = key($ar);
if($key === null){return false;}
$current = current($ar);
try
{
return [$key,$current,'key'=>$key,'value'=>$current];
}finally{
next($ar);
};
}
/**
* Get all menu items from database
*/
function get_menu_items()
{
// Change the field names and the table name in the query below to match tour needs
return [
['id'=>1, 'parent_id'=>0, 'title'=>'title 1','link'=>'link 1','position'=>'0'],
['id'=>2, 'parent_id'=>1, 'title'=>'title 2','link'=>'link 2','position'=>'0'],
['id'=>3, 'parent_id'=>1, 'title'=>'title 3','link'=>'link 3','position'=>'0'],
['id'=>4, 'parent_id'=>0, 'title'=>'title 4','link'=>'link 4','position'=>'0'],
];
}
/**
* Build the HTML for the menu
*/
function get_menu_html( $root_id = 0 )
{
$this->html = array();
$this->items = $this->get_menu_items();
foreach ( $this->items as $item )
$children[$item['parent_id']][] = $item;
// loop will be false if the root has no children (i.e., an empty menu!)
$loop = !empty( $children[$root_id] );
// initializing $parent as the root
$parent = $root_id;
$parent_stack = array();
// HTML wrapper for the menu (open)
$this->html[] = '<ul>';
while ( $loop && ( ( $option = $this->each( $children[$parent] ) ) || ( $parent > $root_id ) ) )
{
if ( $option === false )
{
$parent = array_pop( $parent_stack );
// HTML for menu item containing childrens (close)
$this->html[] = str_repeat( "\t", ( count( $parent_stack ) + 1 ) * 2 ) . '</ul>';
$this->html[] = str_repeat( "\t", ( count( $parent_stack ) + 1 ) * 2 - 1 ) . '</li>';
}
elseif ( !empty( $children[$option['value']['id']] ) )
{
$tab = str_repeat( "\t", ( count( $parent_stack ) + 1 ) * 2 - 1 );
// HTML for menu item containing childrens (open)
$this->html[] = sprintf(
'%1$s<li><a href="%2$s">%3$s</a>',
$tab, // %1$s = tabulation
$option['value']['link'], // %2$s = link (URL)
$option['value']['title'] // %3$s = title
);
$this->html[] = $tab . "\t" . '<ul class="submenu">';
array_push( $parent_stack, $option['value']['parent_id'] );
$parent = $option['value']['id'];
}
else
// HTML for menu item with no children (aka "leaf")
$this->html[] = sprintf(
'%1$s<li><a href="%2$s">%3$s</a></li>',
str_repeat( "\t", ( count( $parent_stack ) + 1 ) * 2 - 1 ), // %1$s = tabulation
$option['value']['link'], // %2$s = link (URL)
$option['value']['title'] // %3$s = title
);
}
// HTML wrapper for the menu (close)
$this->html[] = '</ul>';
return implode( "\r\n", $this->html );
}
}
$menu = new MenuBuilder();
echo '<pre>' . $menu->get_menu_html() . '</pre>';
?>
我从检查第三个 while 循环条件开始进行 foreach。
$this->html = array();
$this->items = $this->get_menu_items();
foreach ($this->items as $item)
$children[$item['parent_id']][] = $item;
// loop will be false if the root has no children (i.e., an empty menu!)
$loop = !empty($children[$root_id]);
// initializing $parent as the root
$parent = $root_id;
$parent_stack = array();
// HTML wrapper for the menu (open)
$this->html[] = '<ul>';
if ($loop) {
foreach ($children[$parent] as $option) {
if ($parent > $root_id) {
break; // exit loop
}
if ($option === false) {
$parent = array_pop($parent_stack);
// HTML for menu item containing childrens (close)
$this->html[] = str_repeat("\t", (count($parent_stack) + 1) * 2) . '</ul>';
$this->html[] = str_repeat("\t", (count($parent_stack) + 1) * 2 - 1) . '</li>';
} elseif (!empty($children[$option['id']])) {
$tab = str_repeat("\t", (count($parent_stack) + 1) * 2 - 1);
// HTML for menu item containing childrens (open)
$this->html[] = sprintf(
'%1$s<li><a href="%2$s">%3$s</a>',
$tab, // %1$s = tabulation
$option['link'], // %2$s = link (URL)
$option['title'] // %3$s = title
);
$this->html[] = $tab . "\t" . '<ul class="submenu">';
array_push($parent_stack, $option['parent_id']);
$parent = $option['id'];
} else
// HTML for menu item with no children (aka "leaf")
$this->html[] = sprintf(
'%1$s<li><a href="%2$s">%3$s</a></li>',
str_repeat("\t", (count($parent_stack) + 1) * 2 - 1), // %1$s = tabulation
$option['link'], // %2$s = link (URL)
$option['title'] // %3$s = title
);
}
// HTML wrapper for the menu (close)
$this->html[] = '</ul>';
return implode("\r\n", $this->html);
}
测试:
[
['id'=>1, 'parent_id'=>0, 'title'=>'title 1','link'=>'link 1','position'=>'0'],
['id'=>2, 'parent_id'=>1, 'title'=>'title 2','link'=>'link 2','position'=>'0'],
['id'=>3, 'parent_id'=>1, 'title'=>'title 3','link'=>'link 3','position'=>'0'],
['id'=>4, 'parent_id'=>0, 'title'=>'title 4','link'=>'link 4','position'=>'0'],
];