PHP mysqli递归查询层级产品 如何限制含子产品的返回总数
实现层级产品列表总数限制的方案
你遇到的计数器失效问题,核心原因是递归调用时普通变量按值传递,各层递归的计数变量独立不共享,深层修改的计数无法同步到上层。以下两种方案都可以稳定实现最多返回8条全层级产品的需求:
方案1:最小改动修复现有PHP递归逻辑
只需要把计数变量改为引用传递,在每次输出、递归前判断是否达到数量上限即可,不需要调整原有输出结构,修改后的可运行代码如下:
function get_the_list($id = 0, $owner_id = 1, &$count = 0, $maxLimit = 8, $depth = 1) { $list = ''; // 达到上限直接终止 if ($count >= $maxLimit) return $list; // 数据库连接请替换为你自己的配置,这里用预处理避免SQL注入 $conn = mysqli_connect("数据库地址", "账号", "密码", "库名"); $stmt = mysqli_prepare($conn, "SELECT id, product_title, main_id FROM products WHERE main_id = ? AND owner_id = ?"); mysqli_stmt_bind_param($stmt, "ii", $id, $owner_id); mysqli_stmt_execute($stmt); $result = mysqli_stmt_get_result($stmt); $loopI = 0; while ($row = mysqli_fetch_assoc($result)) { if ($count >= $maxLimit) break; $loopI++; $count++; // 保留原输出格式 $list .= str_repeat(" ", $depth-1) . "({$row['main_id']}) i: {$loopI} --- loop: {$count}, {$depth} - {$row['product_title']}<br>"; // 注意:原代码递归传参有误,查当前产品的子级需要传当前行的id,而非main_id,否则会死循环 $list .= get_the_list($row['id'], $owner_id, $count, $maxLimit, $depth+1); } mysqli_stmt_close($stmt); return $list; } // 初始化调用 $totalCount = 0; echo get_the_list(0, 1, $totalCount);
该方案下计数变量全程全局共享,不会受递归深度影响,计数到8时会自动终止所有层级的查询和输出,和你预期的“查到Rearview mirror就终止”的逻辑完全一致。
方案2:SQL递归CTE一次性查询(推荐,性能更高)
如果你的数据库是MySQL 8.0+、PostgreSQL等支持递归CTE的版本,可以直接在SQL层完成层级遍历、排序、数量截断,不需要PHP层递归发多次查询,性能提升明显,SQL语句如下:
WITH RECURSIVE product_hierarchy AS ( -- 锚点:查询所有顶级主产品 SELECT id, product_title, main_id, 1 AS depth, CAST(id AS CHAR(200)) AS sort_path FROM products WHERE main_id = 0 AND owner_id = 1 UNION ALL -- 递归:关联查询所有子产品 SELECT p.id, p.product_title, p.main_id, ph.depth + 1 AS depth, CONCAT(ph.sort_path, '-', p.id) FROM products p JOIN product_hierarchy ph ON p.main_id = ph.id WHERE p.owner_id = 1 ) -- 按深度优先的遍历顺序排序,直接取前8条 SELECT * FROM product_hierarchy ORDER BY sort_path LIMIT 8;
查询结果直接返回按你原有层级顺序排列的8条产品,PHP端只需要一次查询拿到结果,遍历输出格式即可,完全不存在递归计数失效的问题。
内容的提问来源于stack exchange,提问作者Miedzegadze
相关产品推荐
相关产品推荐

