0

I have a problem where I want to catch all exception except descendants of my custom exception.

Maybe bad design, but here it is (Simplified and names changed, but the code is quite accurate):

function doStuff()
{
    try {
        // code
        if (something) {
            // manually throw an exception
            throw StuffError("Something is bad.");
        }

        // a third-party code, can throw exceptions
        LibraryClass::arcaneMagic();

    } catch (Exception $e) {
        throw new StuffError("Error occured while doing stuff: "
             . $e->getMessage());
    }
}

/** My custom exception */
class StuffError extends Exception
{
    function __construct($msg) {
        parent::__construct('StuffError: ' . $msg);
    }
}

However, the issue here is that I don't want the try-catch to intercept the manually throws StuffError. Or, seamlessly rethrow it or something.

As it is now, I'd get:

StuffError: Error occured while doing stuff: StuffError: Something is bad.

I want just:

StuffError: Something is bad.

How would I do it?

4
  • Why are you throwing the same type of exception you are catching in your catch block? Why extend Exception at all in this case? You are not really adding any functionality other than concatenating a string. If anything you might want to override getMessage method to get custom behavior. Commented Aug 15, 2014 at 20:27
  • Yes, or something that extends it. I would like to avoid instanceof checking, but if that's my only chance, it's OK I guess. Commented Aug 15, 2014 at 20:28
  • So what are you actually trying to do? It is not clear to me. Commented Aug 15, 2014 at 20:31
  • @MikeBrant catch all that is not my custom exception, and somehow wrap it so it can be selectively caught higher in the call hierarchy. I want all fails to be reported as a "StuffError". Commented Aug 15, 2014 at 20:33

2 Answers 2

2

You can have multiple catch clauses, and the first one that matches will be the one that runs. So you could have something like this:

try {
    do_some_stuff();
}
catch (StuffError $e) {
    throw $e;
}
catch (Exception $e) {
    throw new StuffError(Error occurred while doing stuff: " . $e->getMessage());
}

But you might want to rethink wrapping stuff like this. It obscures the real cause of the error. For one thing, you lose the stack trace. But it also complicates error handling, since now someone can't differentiate exception types the way you're trying to do, short of trying to parse the exception message (which is rather an anti-pattern in itself).

Sign up to request clarification or add additional context in comments.

2 Comments

That's the thing I have to avoid, losing the stack trace.
@MightyPork: You can somewhat avoid that by passing $e to your constructor, like new StuffError("insert message here", $e->getCode(), $e). (In 5.3+, exceptions let you pass a "previous exception", which is the exception that caused the one you're throwing.) But really, unless you absolutely have to, you get a cleaner trace by not trying to intercept and wrap them at all.
0

I might be misinterpreting you, but I think this is what you're looking for:

    ...

} catch (Exception $e) {
    if (get_class($e) == 'StuffError' || is_subclass_of($e, 'StuffError')) {
        throw $e;
    } else {
        throw new StuffError("Error occured while doing stuff: "
             . $e->getMessage());
    }
}

    ...

Replace your catch statement with the code above. It checks to see if the exception is a StuffError or a child class of StuffError. I'm still very confused at why you would need to throw a StuffError exception after you catch, but maybe that's just some weirdness coming from translating/cleaning your code.

3 Comments

For reference, you can say $e instanceof StuffError to make the type check look a bit less hideous. But eh...
To each his own, I find operators like that very hard to read. I also prefer to be as explicit as possible in my comparisons to avoid ambiguity. You're right though, instanceof will work.
You could also use is_a($e, 'StuffError') if you wanted to avoid instanceof. It'll return true for a StuffError as well as any subtype.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.