ThinkPHP 內建 list_to_tree() 函數可將扁平數據轉為樹狀結構,但預設只輸出頂層節點 (含 _child 遞歸)。若需一次性列出所有節點 (如下拉選單、權限樹),需額外遞歸遍歷。
<?php
public function index() {
Load('extend'); // 載入 extend.php (含 list_to_tree)
$Category = D('Category');
// 1. 獲取扁平數據,按排序字段排序 (重要:同級順序)
$list = $Category->order('sort DESC')->select();
// 2. 轉為樹狀結構
// list_to_tree($list, '主鍵', '父鍵', '子節點鍵名', '根節點pid值')
$tree = list_to_tree($list, 'id', 'fid', '_child', 0);
// 3. 遞歸展平所有節點
$flat = $this->flattenTree($tree);
dump($flat); // 或輸出 JSON 給前端
}
protected function flattenTree($tree) {
static $result = array();
foreach ($tree as $node) {
$result[] = $node; // 當前節點
if (isset($node['_child']) && is_array($node['_child'])) {
$this->flattenTree($node['_child']); // 遞歸子節點
}
}
return $result;
}
?>
<?php
/**
* 扁平數組轉樹狀結構
* @param array $list 數據集
* @param string $pk 主鍵名 (默認 id)
* @param string $pid 父鍵名 (默認 pid)
* @param string $child 子節點鍵名 (默認 _child)
* @param mixed $root 根節點 PID 值 (默認 0)
* @return array
*/
function list_to_tree($list, $pk='id', $pid='pid', $child='_child', $root=0) {
$tree = array();
if (is_array($list)) {
$refer = array();
foreach ($list as $key => $data) {
$refer[$data[$pk]] =& $list[$key]; // 關鍵:引用賦值
}
foreach ($list as $key => $data) {
$parentId = $data[$pid];
if ($root == $parentId) {
$tree[] =& $list[$key];
} elseif (isset($refer[$parentId])) {
$parent =& $refer[$parentId];
$parent[$child][] =& $list[$key];
}
}
}
return $tree;
}
/**
* 數組多字段排序
* @param array $list
* @param string $field 排序字段
* @param string $sortby asc|desc|nat
* @return array
*/
function list_sort_by($list, $field, $sortby='asc') {
if (is_array($list)) {
$refer = array();
foreach ($list as $i => $data) $refer[$i] = &$data[$field];
switch ($sortby) {
case 'asc': asort($refer); break;
case 'desc': arsort($refer); break;
case 'nat': natcasesort($refer); break;
}
$result = array();
foreach ($refer as $key => $val) $result[] = &$list[$key];
return $result;
}
return false;
}
/**
* 數組條件搜尋
* @param array $list
* @param mixed $condition array('field'=>val) 或 'field=val'
* @return array
*/
function list_search($list, $condition) {
if (is_string($condition)) parse_str($condition, $condition);
$result = array();
foreach ($list as $key => $data) {
$match = true;
foreach ($condition as $field => $value) {
if (!isset($data[$field])) { $match = false; break; }
if (0 === strpos($value, '/')) { // 正則模式 /pattern/
$match = preg_match($value, $data[$field]);
} elseif ($data[$field] != $value) {
$match = false;
}
}
if ($match) $result[] = &$list[$key];
}
return $result;
}
?>
$refer[$pk] =& $list[$key] 避免複製大數組,節省內存,修改同步order('sort DESC') 確保同級節點順序正確,否則樹結構順序混亂0 或 null,視資料表設計而定static $result 累積,避免層層返回合併的性能開銷<select name="category_id">
<?php foreach ($flat as $node): ?>
<option value="<?php echo $node['id']; ?>"
style="padding-left: <?php echo $node['level'] * 20; ?>px;">
<?php echo str_repeat('— ', $node['level']) . $node['name']; ?>
</option>
<?php endforeach; ?>
</select>
注意:list_to_tree 不自動生成 level 字段,展平時可額外計算或前端根據父子關係動態縮進。