3

I usually indicate an error in a method by returning false, but it doesn't always gel with me semantically (as depending on the method, false may be a valid return).

I've looked into exceptions, and am wondering are they a one-size-fits-all solution? Should I return false where I can still?

I may be completely missing the point here so please bear with me.

// My old way
function getProductById($id) {

    if ( ! is_numeric($id)) {
         return false;     
    }

}

// My consideration
function getProductById($id) {

    if ( ! is_numeric($id)) {
         throw new Exception('The id must be numerical!');     
    }

}
alex
  • 479,566
  • 201
  • 878
  • 984
  • 1
    I answered a similar question once, the answers there might be useful, too: http://stackoverflow.com/questions/1069617/would-i-want-to-throw-an-exception-or-an-error-in-this-php-script/1069640 – soulmerge Nov 27 '09 at 06:13

4 Answers4

2

My train of thought is this:

If a piece of code can't do its work because a pre-condition failed, throw an exception.

So, if your getProductById() method wasn't provided with the correct type of value to be able to do what it's supposed to, that's a reason to throw an exception.

This allows you to spot problems much quicker, because of the clear distinction between "no result" and "potentially invalid state". It gives you peace of mind, if you get used to throwing an exception in such cases, because it'll fail hard instead of going on in an undefined / unexpected way.

I'd return false or null, if everything worked as it was supposed to (as defined), but the process just didn't find a matching product.

P.S.: That's also why throwing exceptions from input validation is wrong per my definition. The whole purpose of the code was to validate the inputs, so invalid inputs are to be expected and thus not exceptional.

DanMan
  • 11,323
  • 4
  • 40
  • 61
1

Exceptions are great! The let you keep your error handling code away from your error code.

You're correct that returning false can be a valid answer for a function. If you throw an error you can also catch it and do something more useful.

When I say it helps get your error handling code away from your errors consider this

try {    
    func1($a);  
    func2($b);  
    func3($c);  
} catch (Exception $e) {  
    // error handling here  
}  

So you don't need to check each function for a false return and act on it.

alex
  • 479,566
  • 201
  • 878
  • 984
Slashterix
  • 1,036
  • 1
  • 10
  • 17
  • That's true, I generally agree, BUT you should have mentioned possible performance disadvantages (cost of exceptions)! – Sk8erPeter Mar 31 '12 at 16:21
0

I would recommend using one style only, so if you've written your application by returning false so far, you should consider keeping that up.

But if you want to rewrite your code for exceptions, be aware that exceptions are unusually resource-hungry in PHP (both in CPU time and memory). I'd like to demonstrate by example: Imagine there is a function Product::getById($id). If you want this function to throw an exception if the id was not found, everything is fine. But if you want to call that function a lot within a single page request and collect all non-existent IDs, you might first think of catching the exceptions in a loop. This leads to a huge slowdown. The options are:

  • Duplicate the code (create a function called Product::getByIdWithoutException())
  • create a dedicated function for this use case (Product::getAllIds(array $ids)). This is the best solution, but not always feasible (without rewriting lots of code or having a huge parameter list or breaking with other best-practices of software engineering, etc).

I finally switched to another model, where I passed a parameter to control whether to throw an exception or not. Setting the default value to true allowed me to program lazily without thinking of such error cases and I was able to exchange exceptions for speed by passing an additional argument. This even works if the exception is thrown in other functions, since you can pass that parameter around:

function getById($id, $throwException = true) {
    if (!self::idExists($id)) {
        if ($throwException) {
            throw new IdNotFoundException();
        } else {
            return NULL;
        }
    }
    return self::getByWhereClause('id = ' . self::escape($id), $throwException);
}

Thought you might find that useful.

soulmerge
  • 73,842
  • 19
  • 118
  • 155
  • It's an interesting idea... I don't know yet if I want to clutter my parameter lists with it. – alex Nov 27 '09 at 05:41
0

According to Joel Spolsky, Exceptions shouldn't be used.

My general rule of thumb with regard to exception handling is to first try to maintain application flow for the end user which you could accomplish by just never throwing exceptions in PHP in the first place, but there are times when they are useful.

I tend to look at a decision on whether to throw an exception versus returning a boolean false or some other handling method based on what the conditions are that could lead to the state that triggers the problem.

Is this a normal, plausible value or state to be in when the particular code block is executed? If so, then you probably just want to return a boolean false or some other value indicating that the code block reached a point of failure.

If you concerned that a non-normal value or state might exist, or if the value or state is the result of someone forgetting to properly initialize a variable in the code, then an exception would probably be appropriate because this will provide immediate feedback to you as a developer. A couple of examples here would be of a required property that has to be set in an object constructor but the value is not specified properly or if you have a scenario where a method should not be called on an object you might want to throw an exception if it gets called.

In short, I tend to use the tool that fits best. If I'm dealing with something that is part of normal application execution then I usually return a value to indicate failure. If its a situation where something invalid is happening then I throw an exception so that I deal with the problem.

I suppose you could say that I use exceptions only to catch those things that should truly halt application execution for an end user but I code with the idea in mind that through proper testing none of those lines of code should ever execute in the wild.

Noah Goodrich
  • 24,875
  • 14
  • 66
  • 96