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

递归遍历嵌套Category对象并提取指定属性的技术问询

嵌套Category对象转指定结构数组的实现方案

一、递归实现(直观易维护,推荐)

递归是处理嵌套结构最直接的方式,以下函数可直接将Category对象树转换为你需要的数组结构:

function categoryToTree(Category $category): array
{
    // 构建当前分类的基础数据节点
    $treeNode = [
        'title' => $category->getTitle(),
        'url' => $category->getLink(),
        'parent' => $category->getParentCategory()?->getId() ?? null,
        'children' => []
    ];

    // 递归处理所有可见子分类
    if ($category->getHasVisibleSubCats()) {
        foreach ($category->getSubCats() as $subCatId => $subCategory) {
            $treeNode['children'][$subCatId] = categoryToTree($subCategory);
        }
    }

    // 返回以当前分类ID为顶级键的嵌套结构
    return [$category->getId() => $treeNode];
}

代码说明

  • 每个Category对象被转换为包含title/url/parent/children的标准数组节点
  • 自动递归遍历所有层级的子分类,将子分类的转换结果存入父节点的children数组(以子分类ID为键)
  • 最终输出直接兼容json_encode,无需额外处理

使用示例

// 传入根Category对象
$result = categoryToTree($oInputCat);
// 输出格式化后的JSON
echo json_encode($result, JSON_PRETTY_PRINT);

你现有代码的问题分析

  • buildTree_v1:错误地遍历了子分类对象的属性(foreach ($oSubCat as &$oSubChild)),应直接递归处理$oSubCat;同时子分类应存入children键,而非直接作为当前节点的子键。
  • buildTree_v2:仅收集了分类ID,未提取title/url等核心属性,无法满足最终JSON结构需求。

二、RecursiveIteratorIterator实现

如果你希望用迭代器方式处理,可通过自定义递归迭代器扁平化遍历所有节点,再构建嵌套结构:

1. 自定义RecursiveCategoryIterator

class RecursiveCategoryIterator implements RecursiveIterator
{
    private $category;
    private $subCats;
    private $position = 0;

    public function __construct(Category $category)
    {
        $this->category = $category;
        $this->subCats = $category->getSubCats();
    }

    public function current(): Category
    {
        return current($this->subCats);
    }

    public function key(): string
    {
        return key($this->subCats);
    }

    public function next(): void
    {
        next($this->subCats);
        $this->position++;
    }

    public function rewind(): void
    {
        reset($this->subCats);
        $this->position = 0;
    }

    public function valid(): bool
    {
        return $this->position < count($this->subCats);
    }

    public function hasChildren(): bool
    {
        return $this->current()->getHasVisibleSubCats();
    }

    public function getChildren(): RecursiveIterator
    {
        return new self($this->current());
    }
}

2. 构建嵌套树的函数

function buildTreeWithIterator(Category $rootCategory): array
{
    // 收集所有节点的基础数据
    $allNodes = [];

    // 添加根节点
    $rootId = $rootCategory->getId();
    $allNodes[$rootId] = [
        'title' => $rootCategory->getTitle(),
        'url' => $rootCategory->getLink(),
        'parent' => $rootCategory->getParentCategory()?->getId() ?? null,
        'children' => []
    ];

    // 遍历所有子节点(SELF_FIRST模式:先处理当前节点,再处理子节点)
    $iterator = new RecursiveIteratorIterator(
        new RecursiveCategoryIterator($rootCategory),
        RecursiveIteratorIterator::SELF_FIRST
    );

    foreach ($iterator as $subCatId => $subCategory) {
        $allNodes[$subCatId] = [
            'title' => $subCategory->getTitle(),
            'url' => $subCategory->getLink(),
            'parent' => $subCategory->getParentCategory()->getId(),
            'children' => []
        ];

        // 将当前节点关联到父节点的children数组
        $parentId = $subCategory->getParentCategory()->getId();
        if (isset($allNodes[$parentId])) {
            $allNodes[$parentId]['children'][$subCatId] = &$allNodes[$subCatId];
        }
    }

    // 返回以根节点ID为顶级键的结构
    return [$rootId => $allNodes[$rootId]];
}

代码说明

  • 自定义迭代器实现了RecursiveIterator接口,让系统能识别Category的嵌套子节点
  • 通过扁平化遍历收集所有节点数据,再通过parent字段将子节点挂载到对应父节点的children数组中
  • 同样支持任意层级的嵌套分类结构

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.26 09:15:35