PHP中使用PDO动态构建多级菜单问题排查
问题分析与解决方案
你的问题很明确——当前代码只硬编码处理了两层节点(根节点+直接子节点),没有处理子节点的子节点,所以深层的Husam、Khalaf和Mark都没被渲染出来。要处理这种无限层级的树形结构,我们需要用递归函数来实现。
修复方案:递归渲染树形结构
我们可以把渲染子节点的逻辑抽成一个独立的递归函数,让它自动遍历所有层级的节点:
public function familyTree() { // 查询根节点(parent为NULL的节点) $query = "SELECT id, nameOfPerson, parent FROM person WHERE parent IS NULL"; $statement = $this->db->prepare($query); $statement->execute(); echo '<ul id="family">'; while ($family = $statement->fetch(PDO::FETCH_OBJ)) { echo '<li>' . $family->nameOfPerson; // 调用递归函数处理当前节点的子节点 $this->renderChildren($family->id); echo '</li>'; } echo '</ul>'; } // 递归渲染子节点的私有函数 private function renderChildren($parentId) { $query = "SELECT id, nameOfPerson, parent FROM person WHERE parent = :id"; $statement = $this->db->prepare($query); $statement->bindValue(':id', $parentId); $statement->execute(); if ($statement->rowCount() > 0) { echo '<ul>'; while ($child = $statement->fetch(PDO::FETCH_OBJ)) { echo '<li>' . $child->nameOfPerson; // 递归调用,处理当前子节点的子节点 $this->renderChildren($child->id); echo '</li>'; } echo '</ul>'; } }
工作原理
familyTree函数负责初始化根节点的查询与渲染,对每个根节点,调用renderChildren处理它的直接子节点。renderChildren函数接收一个父ID,查询该父ID下的所有子节点;如果存在子节点,就渲染一个<ul>容器,然后对每个子节点:- 渲染
<li>展示节点名称 - 递归调用自身,处理这个子节点的子节点
- 直到某个节点没有子节点时,递归终止
- 渲染
这样不管你的树形结构有多少层(比如John→Michel→Husam→Khalaf/Mark),都会被完整渲染出来。
性能优化:一次性查询构建树形结构
如果你的数据量较大,多次递归查询数据库会增加性能开销。可以先一次性查询所有数据,在内存中构建树形结构后再渲染:
public function familyTree() { // 一次性查询所有人员数据 $query = "SELECT id, nameOfPerson, parent FROM person"; $statement = $this->db->prepare($query); $statement->execute(); $allPersons = $statement->fetchAll(PDO::FETCH_ASSOC); // 构建内存树形结构:以parent值为键,存储对应子节点列表 $tree = []; foreach ($allPersons as $person) { $parentId = $person['parent'] ?? null; $tree[$parentId][] = $person; } // 渲染根节点(parent为NULL的节点) echo '<ul id="family">'; $this->renderTree($tree, null); echo '</ul>'; } private function renderTree($tree, $parentId) { // 如果当前父ID没有子节点,直接返回 if (!isset($tree[$parentId]) || empty($tree[$parentId])) { return; } foreach ($tree[$parentId] as $person) { echo '<li>' . $person['nameOfPerson']; echo '<ul>'; // 递归渲染当前节点的子节点 $this->renderTree($tree, $person['id']); echo '</ul>'; echo '</li>'; } }
这个方案只需要执行一次数据库查询,性能更优,适合数据量较大的场景。
内容的提问来源于stack exchange,提问作者Second View
相关产品推荐
相关产品推荐

