0

I have this recursive function up and running:

function my_function($a, $b, $level=0){


    $items = get_some_items($a, $b);

    $fh = fopen($fpath, 'a+');

    foreach($items as $item){
        fwrite($fh, "Some info related to $item");

        if( /* $item has something special */ ){

            my_function($a, $item, $level++);
        }
    }


    if( /* we a re at the last recursion */ ){
        //do something extra special;
        //e.g. fwrite($fh, "This is the end of the file");
    }


    fclose($fh);

}

With this, I can tell which iteration is the first run. I can also get the nth run at any level.

My question: I'd like to do something special during the very last run. Is there even a way to neatly achieve this?

Ifedi Okonkwo
  • 3,406
  • 4
  • 33
  • 45
  • Related: https://stackoverflow.com/questions/1070244/how-to-determine-the-first-and-last-iteration-in-a-foreach-loop – k0pernikus Oct 11 '19 at 08:49
  • Use count on items and add another param you pass before the last call – SeRu Oct 11 '19 at 08:52
  • Same as you do with `level`, you could inject a parameter indicating last call. Do you want to know the last call inside the foreach loop and the last ever invocation of `my_function` within the recursive stack? – k0pernikus Oct 11 '19 at 08:53
  • How do you know the number of times that your function is going to be running? If you can't, then adding an extra counting variable doesn't really help. – Koala Yeung Oct 11 '19 at 09:06
  • What is the "something special" that you planned to do in the last iteration, anyway? – Koala Yeung Oct 11 '19 at 09:07
  • @KoalaYeung. Your comment/question is a very good one. Nope, I do NOT know the number of times the function is going to be running. For as long as `get_some_items()` returns any items, we need to loop through them and run `my_function` on each element. – Ifedi Okonkwo Oct 11 '19 at 09:59
  • @KoalaYeung, to answer your question about "something special", I have edited the code, adding the filesystem functions. (i.e. I need to write something to a text file). – Ifedi Okonkwo Oct 11 '19 at 10:08
  • @IfediOkonkwo: By "last recursion", do you mean the end of the main loop of your outermost function call? Or do you mean the last inner recursion call? Or do you mean the last inner recursion call with the deepest recursion depth? – Koala Yeung Oct 12 '19 at 00:35

3 Answers3

1

You could add a new param at the end that only returns true if the item number you are on is the same as the total number of items.

If I am honest, the function is a little confusing to me because it doesn't seem to care if level one is both the first and the last. So I am assuming this function only cares about the last item as long is it has a parent.

function my_function($a, $b, $level=0,$isLast=false){
    if($isLast){
        // Do something special on last item
    }
    $items = get_some_items($a, $b);    
    $total = count($items);
    $c=0;
    foreach($items as $item){
        $c++;
        my_function($a, $item, $level++,($c==$total));
    }

    // Additional check maybe to see if the first ever call is also the last?
    if($total==0 && $level<1){
        // Do something special on last item?
        // This could be at the top in the same IF statement
        // as the $isLast check (preferred) if things were moved around.
    }
}
Koala Yeung
  • 7,475
  • 3
  • 30
  • 50
Watts Epherson
  • 692
  • 5
  • 9
  • I think the problem with the boolean `($c==$total)` is that there'll be multiple levels at which `$isLast` will evaluate to `true`. Don't forget, we're not just looping with `foreach`, we're also doing a recursion. – Ifedi Okonkwo Oct 11 '19 at 09:55
1

Just check if you're on a leaf node:

function my_function($a, $b, $level=0){
    $items = get_some_items($a, $b);
    if ($items) {
        foreach($items as $item){
            if( /* $item has something special */ ){
                my_function($a, $item, $level++);
            }
        }
    } else {
        /* we are at the last recursion */ 
        do_something_extra_special();
    }
}
Guillermo Phillips
  • 2,176
  • 1
  • 23
  • 40
  • @Guillero, could you throw some light on the answer. To begin with, pardon my ignorance, but what's even a "leaf node" in this situation? – Ifedi Okonkwo Oct 11 '19 at 09:57
  • Often recursion is used to traverse through a tree of data. You start the the 'trunk' and then at each point you traverse through each branch ($items) until you hit a point where there are no more branches left, i.e. the leaves of the tree. Each point were you split into branches is called a node. So a 'leaf node' is the end of the recursion. – Guillermo Phillips Oct 11 '19 at 13:13
0

Your $level is strangely passed on as $level++, which would increment every time in your foreach loop. Usually when you want to have a level indicator in a recursive function call, all subsequence calls to itself would receive a level indicator of current level + 1.

If so, then your first recursion depth would always have a $level of 0. You may simply check the $level and learn if it is the end of the main loop in your outer-most call.

function my_function($a, $b, $level=0){


    $items = get_some_items($a, $b);

    $fh = fopen($fpath, 'a+');

    foreach($items as $item){
        fwrite($fh, "Some info related to $item");

        if( /* $item has something special */ ){

            my_function($a, $item, $level+1); // changed $level++ to $level+1
        }
    }


    if ($level === 0) { // check if it is the outermost call
        //do something extra special;
        //e.g. fwrite($fh, "This is the end of the file");
    }


    fclose($fh);

}
Koala Yeung
  • 7,475
  • 3
  • 30
  • 50