You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

PHP嵌套foreach循环问题:子分类仅显示在首个父分类下

解决PDO分类循环中子分类仅显示在第一个父分类的问题

嘿,我完全懂你碰到的这个麻烦——所有子分类都挤在第一个父分类下面,后面的父分类压根看不到对应的子分类对吧?你自己排查的结论一点没错:PDOStatement对象在遍历一次之后,内部指针会停在结果集的末尾,后续再去遍历它就拿不到任何数据了。

下面给你几个简单可行的解决办法,挑你觉得顺手的用就行:

方法一:把子分类结果集转成数组(最推荐)

直接把PDO查询到的子分类结果转换成PHP数组,这样每次遍历的都是数组本身,不存在指针位置的问题。改动很小,代码也更直观:

/* Queries */
$categories = $conn->query('SELECT pc.name, pc.ID, COUNT(p.id) AS amount FROM productcategory AS pc INNER JOIN products AS p ON p.categoryID = pc.ID WHERE p.available = 1 GROUP BY pc.ID');
$categories->execute();

// 先把子分类查询结果转成关联数组
$subcategoriesStmt = $conn->query('SELECT pcs.name, pcs.categoryID, pcs.ID FROM productsubcategory AS pcs GROUP BY pcs.ID');
$subcategoriesStmt->execute();
$subcategories = $subcategoriesStmt->fetchAll(PDO::FETCH_ASSOC); // 关键一步:转成数组

foreach ($categories as $category) {
    // 简化选中状态的判断逻辑
    $class = isset($_GET['categorie']) && $category["name"] === $_GET['categorie'] ? 'class="selected"' : '';
?>
<li><a href="?categorie=<?php echo $category["name"]; ?>" <?php echo $class; ?>><?php echo $category["name"] . ' ('. $category["amount"] .')'; ?></a></li>
<?php
    // 遍历子分类数组,每个父分类都会从头开始遍历
    foreach ($subcategories as $subcategory) {
        if($subcategory['categoryID'] == $category['ID']) {
            // 给子分类也加上选中状态判断(可选,看你需求)
            $subClass = isset($_GET['categorie']) && $subcategory["name"] === $_GET['categorie'] ? 'class="selected"' : '';
?>
<li class="sub-cat"><a href="?categorie=<?php echo $subcategory["name"]; ?>" <?php echo $subClass; ?>><?php echo $subcategory["name"]; ?></a></li>
<?php
        }
    }
}

方法二:每次遍历子分类前重置指针

如果你不想转数组,也可以在每次遍历子分类之前,调用rewind()方法把PDOStatement的指针重置到结果集开头:

// 原查询部分不变...
foreach ($categories as $category) {
    // 选中状态判断...
?>
<li><a href="?categorie=<?php echo $category["name"]; ?>" <?php echo $class; ?>><?php echo $category["name"] . ' ('. $category["amount"] .')'; ?></a></li>
<?php
    // 重置子分类结果集的指针到开头
    $subcategories->rewind();
    foreach ($subcategories as $subcategory) {
        if($subcategory['categoryID'] == $category['ID']) {
            // 子分类输出...
        }
    }
}

这种方法也能解决问题,但相比转数组,它依赖PDOStatement的内部状态,稳定性稍差一点,所以更推荐第一种方法。

方法三:优化数据库查询(性能更优)

如果想进一步优化,可以通过一次查询把父分类和子分类的数据都关联起来,减少数据库交互次数。比如用LEFT JOIN查询,然后在PHP里把数据整理成父分类对应子分类的结构:

// 一次查询拿到所有父分类和子分类数据
$combinedQuery = $conn->query('
    SELECT 
        pc.name AS parent_name, 
        pc.ID AS parent_id, 
        COUNT(p.id) AS parent_amount,
        pcs.name AS sub_name, 
        pcs.ID AS sub_id,
        pcs.categoryID AS sub_parent_id
    FROM productcategory AS pc 
    LEFT JOIN productsubcategory AS pcs ON pc.ID = pcs.categoryID
    LEFT JOIN products AS p ON p.categoryID = pc.ID 
    WHERE p.available = 1 
    GROUP BY pc.ID, pcs.ID
');
$combinedQuery->execute();
$combinedData = $combinedQuery->fetchAll(PDO::FETCH_ASSOC);

// 整理数据:父分类ID为键,值包含父分类信息和子分类列表
$categoryTree = [];
foreach ($combinedData as $item) {
    $parentId = $item['parent_id'];
    if (!isset($categoryTree[$parentId])) {
        $categoryTree[$parentId] = [
            'name' => $item['parent_name'],
            'amount' => $item['parent_amount'],
            'subcategories' => []
        ];
    }
    if (!empty($item['sub_name'])) {
        $categoryTree[$parentId]['subcategories'][] = [
            'name' => $item['sub_name'],
            'id' => $item['sub_id']
        ];
    }
}

// 遍历整理好的分类树输出
foreach ($categoryTree as $category) {
    $class = isset($_GET['categorie']) && $category["name"] === $_GET['categorie'] ? 'class="selected"' : '';
?>
<li><a href="?categorie=<?php echo $category["name"]; ?>" <?php echo $class; ?>><?php echo $category["name"] . ' ('. $category["amount"] .')'; ?></a></li>
<?php
    foreach ($category['subcategories'] as $subcategory) {
        $subClass = isset($_GET['categorie']) && $subcategory["name"] === $_GET['categorie'] ? 'class="selected"' : '';
?>
<li class="sub-cat"><a href="?categorie=<?php echo $subcategory["name"]; ?>" <?php echo $subClass; ?>><?php echo $subcategory["name"]; ?></a></li>
<?php
    }
}

这种方法只需要一次数据库查询,性能更好,而且代码结构更清晰,适合数据量较大的场景。

内容的提问来源于stack exchange,提问作者Pieter

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.15 07:18:16