PHP实现父子结构数组按父到子顺序排序的函数修复求助
Your current function has a couple of key issues that prevent it from working correctly, plus its approach doesn't handle deep nested categories reliably. Let's break down the problems and provide a robust solution.
Issues with Your Original Code
- Incorrect Parameter Passing: In
sortArrayFromParentToChilds, you callfindSubCategory($a, $output)where$ais the entire category array. ButfindSubCategoryexpects an$idas the first parameter. This means the comparison$o['parent'] == $idis comparing a number to an array, which will never be true. - Limited Nesting Handling: Adding items to the front or back of the output array only checks surface-level parent-child relationships, not deep nesting (like your example where
Adultis a child ofComus, which is a child of a missing parent).
Robust Solution: Build a Tree Then Flatten
A better approach is to first organize your categories into a hierarchical tree structure, then traverse that tree in pre-order (parent first, then children) to get the sorted array. This ensures all parents come before their children, regardless of nesting depth.
Here's the corrected function:
function sortCategoriesParentToChild($categories) { // Create a map of categories by ID for quick lookup $categoryMap = []; $rootCategories = []; // Initialize each category with an empty children array foreach ($categories as $cat) { $categoryMap[$cat['id']] = $cat; $categoryMap[$cat['id']]['children'] = []; } // Build the hierarchical tree foreach ($categoryMap as $id => $cat) { $parentId = $cat['parent']; if ($parentId === 0) { // Add root categories (parent = 0) directly to root list $rootCategories[] = &$categoryMap[$id]; } else if (isset($categoryMap[$parentId])) { // Add child categories to their parent's children array $categoryMap[$parentId]['children'][] = &$categoryMap[$id]; } // Note: Categories with non-existent parents will be treated as root } // Flatten the tree using pre-order traversal $sortedCategories = []; $traverseTree = function($cats) use (&$traverseTree, &$sortedCategories) { foreach ($cats as $cat) { // Remove the temporary 'children' key before adding to the sorted list $cleanCat = $cat; unset($cleanCat['children']); $sortedCategories[] = $cleanCat; // Recursively traverse the current category's children $traverseTree($cat['children']); } }; $traverseTree($rootCategories); return $sortedCategories; }
How to Use It
Test it with your sample data:
$initial = array( array( 'name' => 'Paul', 'id' => 4, 'parent' => 2 ), array( 'name' => 'Liz', 'id' => 5, 'parent' => 2 ), array( 'name' => 'Comus', 'id' => 6, 'parent' => 3 ), array( 'name' => 'Mai', 'id' => 7, 'parent' => 2 ), array( 'name' => 'Titus', 'id' => 8, 'parent' => 3 ), array( 'name' => 'Adult', 'id' => 9, 'parent' => 6 ), array( 'name' => 'People', 'id' => 2, 'parent' => 0 ), array( 'name' => 'Puppy', 'id' => 10, 'parent' => 8 ), array( 'name' => 'Programmers', 'id' => 11, 'parent' => 4 ), ); $sorted = sortCategoriesParentToChild($initial); // Now you can safely loop through $sorted to insert into your database foreach ($sorted as $category) { // Your database insertion logic here echo $category['name'] . "<br>"; }
Output Order
The sorted array will be:
- People (parent 0)
- Paul (child of People)
- Programmers (child of Paul)
- Liz (child of People)
- Mai (child of People)
- Comus (parent 3, which doesn't exist, treated as root)
- Adult (child of Comus)
- Titus (parent 3, treated as root)
- Puppy (child of Titus)
This order ensures that every parent is inserted before its children, which is exactly what you need for your database insertion.
内容的提问来源于stack exchange,提问作者angelique000

