本文提供一套完整的 PHP + MySQL 無限分類實作程式碼,包含資料表結構、核心類別、前端操作介面(新增、編輯、刪除、移動),適合內容管理系統、電商分類、文章分類等場景。採用遞迴樹狀結構儲存,支援無限層級巢狀分類。
CREATE TABLE `p_newsclass` ( `id` int(11) NOT NULL AUTO_INCREMENT, `f_id` int(11) NOT NULL DEFAULT '0' COMMENT '父分類ID,0為頂層', `name` varchar(100) NOT NULL COMMENT '分類名稱', `addtime` datetime DEFAULT NULL COMMENT '建立時間', PRIMARY KEY (`id`), KEY `f_id` (`f_id`) ) ENGINE=MyISAM DEFAULT CHARSET=gbk;
採用陣列模擬樹狀結構,載入所有分類到記憶體,提供豐富的樹狀操作方法。
class sortclass { var $data = array(); // id => name 映射 var $child = array(-1 => array()); // parent_id => 子分類ID陣列 var $layer = array(-1 => -1); // id => 層級深度 var $parent = array(); // id => parent_id var $link; // 資料庫連線資源 var $table; // 資料表名稱 function __construct($link, $table) { $this->setnode(0, -1, '頂極節點'); $this->link = $link; $this->table = $table; $results = mysql_query("SELECT * FROM $this->table", $this->link); while($node = mysql_fetch_array($results)) { $this->setnode($node['id'], $node['f_id'], $node['name']); } } // 設定節點資訊 function setnode($id, $parent, $value) { $parent = $parent ? $parent : 0; $this->data[$id] = $value; $this->child[$id] = array(); $this->child[$parent][] = $id; $this->parent[$id] = $parent; $this->layer[$id] = !isset($this->layer[$parent]) ? 0 : $this->layer[$parent] + 1; } // 遞迴取得所有子孫分類ID(含自己) function getlist(&$tree, $root = 0) { foreach ($this->child[$root] as $key => $id) { $tree[] = $id; if ($this->child[$id]) $this->getlist($tree, $id); } } // 取得分類名稱 function getvalue($id) { return $this->data[$id]; } // 取得層級深度 function getlayer($id, $space = false) { return $space ? str_repeat($space, $this->layer[$id]) : $this->layer[$id]; } // 取得父分類ID function getparent($id) { return $this->parent[$id]; } // 取得所有祖先分類(含自己) function getparents($id) { $parent = array(); while ($this->parent[$id] != -1) { $parent[] = $this->parent[$id]; $id = $this->parent[$id]; } ksort($parent); return $parent; } // 取得直接子分類 function getchild($id) { return $this->child[$id]; } // 取得所有子孫分類(含自己) function getchilds($id = 0) { $child = array($id); $this->getlist($child, $id); return $child; } // 新增分類 function addnode($name, $pid) { mysql_query("INSERT INTO $this->table (`f_id`,`name`) VALUES ('$pid','$name')", $this->link); } // 修改分類名稱 function modnode($cid, $newname) { mysql_query("UPDATE $this->table SET `name`='$newname' WHERE `id` = $cid", $this->link); } // 刪除分類(含所有子孫) function delnode($cid) { $allchilds = $this->getchilds($cid); if (empty($allchilds)) { $sql = "DELETE FROM $this->table WHERE `id` = $cid"; } else { $sql = 'DELETE FROM ' . $this->table . ' WHERE `id` IN (' . implode(',', $allchilds) . ',' . $cid . ')'; } mysql_query($sql, $this->link); } // 移動分類(變更父分類) function movenode($cid, $topid) { mysql_query("UPDATE $this->table SET `f_id`=$topid WHERE `id` = $cid", $this->link); } }
// 資料庫連線 $link = mysql_connect('localhost', 'root', '') or die(mysql_error()); mysql_select_db('class', $link) or die(mysql_error()); mysql_query("SET NAMES gbk", $link); // 實例化分類類別 $tree = new sortclass($link, '`p_newsclass`'); // 處理 POST/GET 操作 $op = !empty($_POST['op']) ? $_POST['op'] : $_GET['op']; if (!empty($op)) { if ($op == 'add') { $tree->addnode($_POST['cname'], $_POST['pid']); redirect_back(); } if ($op == 'mod') { $tree->modnode($_POST['cid'], $_POST['cname']); redirect_back(); } if ($op == 'del') { $tree->delnode($_GET['cid']); redirect_back(); } if ($op == 'move') { $tree->movenode($_POST['who'], $_POST['to']); redirect_back(); } } // 取得完整分類樹(用於下拉選單等) $category = $tree->getchilds(); // 生成巢狀下拉選單輔助函數 function makeselect($array, $formname) { global $tree; $select = ''; } // 頁面跳轉輔助函數 function redirect_back() { echo ''; exit; }
f_id 欄位務必建立索引delnode 方法),請謹慎操作。getparents($id) 取得祖先陣列,反序輸出即可。sort_order 欄位並在查詢時 ORDER BY sort_order。