Search code examples
phploopscontinue

Continue bubbling up inside a loop in PHP


I adapted a web script I wrote to fit my needs for some data I need to retrieve from a server. I run this script from a terminal, so error messages are useful information.

The main part of the code is a loop inside a loop, and in that loop I call a function. In this function there's a call to a database. If there is a problem with connecting to the database, I can catch that error with a simple try {} catch(){}, but how should I structure my code so that I can just skip this iteration and move to the next item in the loop? In other words, do a continue only from within a function.

Below is how I would do it, but I am not sure this is the correct way.

foreach ($flavours as $icecream) {
  foreach ($sauces as $sauce) {
    $amount = dessertServings($icecream, $sauce);
    if ($amount != null) {
      // Some other functions like orderDessert, makePricingList and so on
      fwrite(STDOUT, "$amount servings of $icecream with $sauce remaining!\n");
    }
  }
}

dessertServings($icecream, $sauce) {
  try {
    $dbConnection = new Connection("user", "password", "db$icecream$sauce");
    $amountOfServings = $dbConnection->query($icecream, $sauce);
    return $amountOfServings;
  }
  // E.g database connection could not be made
  catch(Exception $e) {
    fwrite(STDERR, $e->getMessage() . "\n");
    return;
  }
}

Is there a better way to do this?

To make things harder, what if the function doesn't actually return anything and thus isn't assigning a value to a variable? How should you deal with that?

foreach ($flavours as $icecream) {
  foreach ($sauces as $sauce) {
    prepareDessert($icecream, $sauce);
    // Other functions, most importantly: eatDessert($dessert)
  }
}

prepareDessert($icecream, $sauce) {
  try {
    $dbConnection = new Connection("user", "password", "db$icecream$sauce");
    $dbConnection->query($icecream, $sauce)->do("prepare");
  }
  // E.g database connection could not be made
  catch(Exception $e) {
    fwrite(STDERR, $e->getMessage() . "\n");
  }
}

In such a case, how do I make sure that when the try fails, the block in the loop never reaches the other functions, we can't eat an ice cream that wasn't prepared in the first place!

Would I use an empty variable that simply returns true on success and false and fail, and execute the following code in the main block only on true? Or is there a better convention for this in PHP?


Solution

  • how should I structure my code so that I can just skip this iteration and move to the next item in the loop

    The first rule of exception handling: do not do exception handling. Allow it to bubble up and catch it when you need it (in your case, in your loop).

    You can also re-throw an exception in your catch, if you want to do some processing within the function (like print to STDERR), but let it bubble up!

    The other more traditional method is to have your function return some kind of error code - the most basic being "true" on success, "false" or "null" on failure like in your first example. I don't see anything wrong with that.

    To make things harder, what if the function doesn't actually return anything and thus isn't assigning a value to a variable? How should you deal with that?

    Throw exceptions, that's their job!

    how do I make sure that when the try fails, the block in the loop never reaches the other functions

    Don't try/catch within the function or re-throw an exception from within your "catch".

    Would I use an empty variable that simply returns true on success and false and fail, and execute the following code in the main block only on true? Or is there a better convention for this in PHP?

    Yes there is a better convention : throw exceptions.