递归遍历嵌套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
相关产品推荐
相关产品推荐

