views:

104

answers:

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 bare 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!');     
    }

}
+1  A: 

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

Your 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.

PHP-Steven
A: 

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
It's an interesting idea... I don't know yet if I want to clutter my parameter lists with it.
alex
A: 

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