PHP递归函数中如何移除对象数组的多余层级
问题
我正在编写一个生成API JSON响应的函数,JSON内容由CMS生成,初始结构和示例相近。现在需要递归遍历数组的每个['children']元素,移除所有title为“Component drop zone”的层级,并将该层级的子元素直接提升到父层级。
现有代码:
function removePropertiesAndEmptyChildren(&$data) { foreach ($data as &$item) { $remove_keys = [ 'uid', 'type', 'enabled', 'category', 'status', 'componentType', 'selected', 'isContainer', 'mimicParent', 'dropzoneId', 'iconColor' ]; foreach($remove_keys as $key) { if (isset($item[$key])) { unset($item[$key]); } } if (isset($item['children']) && empty($item['children'])) { unset($item['children']); } if(is_array($item)) { $this->removePropertiesAndEmptyChildren($item); } } return $data; }
当前函数返回的数组:
[ { "title": "App Bar", "componentId": "cpt_***_app_bar", "uuid": "e985becb-7dc4-471c-937e-d06858b04a41", "parentUid": "root", "children": [ { "parentUid": "cpt_***_app_bar", "title": "Component drop zone", "uuid": "d692d3b0-7434-4b45-93c1-6b9bf610065e" } ] }, { "title": "List View", "componentId": "cpt_***_list_view", "uuid": "764be577-e1b7-4481-9ca7-0a22a74afa2d", "parentUid": "root", "children": [ { "parentUid": "cpt_***_list_view", "title": "Component drop zone", "uuid": "92226f8a-913c-43a0-94e7-f79f77d28104", "children": [ { "title": "Column", "componentId": "cpt_***_column", "uuid": "c15b5a8c-4a7f-4730-bc80-d0396db350f2", "parentUid": "component-drop-zone", "children": [ { "parentUid": "cpt_***_column", "title": "Component drop zone", "uuid": "fd0c1a09-f0cb-4694-9f66-508de2ff5a51", "children": [ { "title": "Hexa Link Button", "componentId": "cpt_***_hexa_link_button", "uuid": "97fe5f5b-8aee-4284-a536-b48c7121a80b", "parentUid": "component-drop-zone" }, { "title": "Hexa Link Button", "componentId": "cpt_***_hexa_link_button", "uuid": "69354116-4b35-4f38-bae5-594714518587", "parentUid": "component-drop-zone" } ] } ] } ] } ] }, { "title": "Pull To Refresh Action", "componentId": "cpt_***_pull_to_refresh_action", "uuid": "ac227b11-359c-41eb-8fc3-a7bad71995f1", "parentUid": "root" } ]
期望得到的数组结构:
[ { "title": "App Bar", "componentId": "cpt_***_app_bar", "uuid": "e985becb-7dc4-471c-937e-d06858b04a41", "parentUid": "root" }, { "title": "List View", "componentId": "cpt_***_list_view", "uuid": "764be577-e1b7-4481-9ca7-0a22a74afa2d", "parentUid": "root", "children": [ { "title": "Column", "componentId": "cpt_***_column", "uuid": "c15b5a8c-4a7f-4730-bc80-d0396db350f2", "parentUid": "component-drop-zone", "children": [ { "title": "Hexa Link Button", "componentId": "cpt_***_hexa_link_button", "uuid": "97fe5f5b-8aee-4284-a536-b48c7121a80b", "parentUid": "component-drop-zone" }, { "title": "Hexa Link Button", "componentId": "cpt_***_hexa_link_button", "uuid": "69354116-4b35-4f38-bae5-594714518587", "parentUid": "component-drop-zone" } ] } ] }, { "title": "Pull To Refresh Action", "componentId": "cpt_***_pull_to_refresh_action", "uuid": "ac227b11-359c-41eb-8fc3-a7bad71995f1", "parentUid": "root" } ]
我尝试过以下代码但未生效:
$newData = []; foreach ($array as $parent => $children) { foreach ($children as $child => $grandchildren) { $newData[$parent] = array_merge($newData[$parent] ?? [], $grandchildren); } } return $newData;
解决方案
你需要调整递归逻辑的顺序,先处理层级替换,再执行属性移除和空字段清理。修改后的函数如下:
function processComponents(&$data) { foreach ($data as &$item) { // 优先处理children层级替换 if (isset($item['children']) && is_array($item['children'])) { $processedChildren = []; foreach ($item['children'] as $child) { // 识别并跳过Component dropzone层级,直接提升其子元素 if ($child['title'] === 'Component drop zone') { if (isset($child['children']) && !empty($child['children'])) { // 递归处理dropzone的子元素,确保深层层级也被处理 $this->processComponents($child['children']); $processedChildren = array_merge($processedChildren, $child['children']); } } else { // 递归处理普通子元素 $this->processComponents([&$child]); $processedChildren[] = $child; } } // 更新children,空数组则移除该字段 if (!empty($processedChildren)) { $item['children'] = $processedChildren; } else { unset($item['children']); } } // 移除不需要的属性 $remove_keys = [ 'uid', 'type', 'enabled', 'category', 'status', 'componentType', 'selected', 'isContainer', 'mimicParent', 'dropzoneId', 'iconColor' ]; foreach($remove_keys as $key) { if (isset($item[$key])) { unset($item[$key]); } } } return $data; }
关键逻辑说明:
- 层级替换:遍历每个item的children时,直接过滤掉title为“Component drop zone”的元素,将其下的子元素合并到父级的children数组中。
- 递归穿透:对所有子元素(包括dropzone的子元素)执行递归处理,确保深层嵌套的dropzone也能被正确替换。
- 空字段清理:处理完children后,若结果为空则移除该字段,匹配预期输出结构。
- 顺序调整:先完成层级处理,再执行属性移除,避免提前删除必要字段影响判断逻辑。
内容的提问来源于stack exchange,提问作者PixelTarget
相关产品推荐
相关产品推荐

