0

I have a categories table with parent_id column, referring to parent category's ID. I need to retrieve all of the ID's that are under a certain category (all of its children & grandchildren) I wrote this recursive function but for some reason it only returns the direct children of the given category id.

What am I missing here?

function subCategoriesList($id, $data=[]){
    $children = Category::whereParentId($id)->get();
    foreach ($children as $child){
        $data[] = $child->id;
        subCategoriesList($child->id, $data);
    }
    return $data;
}
  • Also covered by "[Recursive function in PHP function : how to prevent return value?](/q/30725648/90527)", "[struggling to walk through php array element in recursive function](https://stackoverflow.com/q/47790314/90527)", "[rebuilding a tree as flat array](/q/27297496/90527)", "[Algorithm to find amount of levels in an array of arrays](/q/28382934/90527)" – outis Oct 09 '22 at 21:21

2 Answers2

1

You're not passing $data by reference, but you're making the recursive call as if you are.

Try:

function subCategoriesList($id){
    $data=[]
    $children = Category::whereParentId($id)->get();
    foreach ($children as $child){
        $data[] = $child->id;
        $data = array_merge($data, subCategoriesList($child->id));
    }
    return $data;
}

Conversely, and for completeness, with references:

function subCategoriesList($id, &$data){
    $children = Category::whereParentId($id)->get();
    foreach ($children as $child){
        $data[] = $child->id;
        subCategoriesList($child->id, $data);
    }
}

// You must call it as follows, though
$my_data = [];
subCategoriesList($some_id, $my_data);

Personally, though, I tend to recommend that references be avoided unless there is a clear reason for them. IMO they tend to result in confusing code and side-effects, while rarely delivering the benefits that the writer thinks they are getting.

Sammitch
  • 30,782
  • 7
  • 50
  • 77
  • I didn't know I had to do that! Thanks so much! It's returning same child category 6 times but nothing I can't handle there was an array_unique function for that I believe. – Kemal Özvarol Oct 07 '22 at 23:28
  • 1
    Well unless there's a subcategory that has 6 parents, there's probably a logic issue in there to be resolved. I didn't have any usable test data to actually run while I wrote this. – Sammitch Oct 07 '22 at 23:32
  • 1
    Oh I think we need to get rid of `$data` from the parameter list. There's no need for it to be there in the non-reference version. – Sammitch Oct 07 '22 at 23:34
1

You're not doing anything with the returndata when you call subCategoriesList within the function.

subCategoriesList($child->id, $data);

should be

$data = array_merge($data, subCategoriesList($child->id, $data));
Rick Muller
  • 17
  • 1
  • 7