HiveBrain v1.2.0
Get Started
← Back to all entries
debugphpMinor

Throw an exception which contains a nested set of previous exceptions

Submitted by: @import:stackexchange-codereview··
0
Viewed 0 times
exceptionspreviousexceptionwhichnestedcontainsthrowset

Problem

I have a set of domain objects which try to find a solution to a problem.

The top level object has an algorithm which splits up the problem and delegates it to lower level objects, which in turn do the same.

I want the top level algorithm to throw an exception if it did not find any solutions, giving a breakdown of possible causes.

My question is, how should(n't) this be implemented?

The way I was thinking of doing this:

The algorithms at all levels throw an exception if it fails to find a solution.

For a given level, call it the parent algorithm, it would accumulate exceptions thrown by its children, and if all attempts by its children throw an exception, the parent will itself throw an exception which contains its childrens' exceptions.

My implementation is as follows:

class ExceptionWithCauses extends \Exception {

    private $causes = array();

    public function addCause(\Exception $ex){
        $this->causes[] = $ex;
        $this->message .= "\n".$ex->getMessage();
    }

}


I'm using it like this:

function findAnOption()
{
    $noOptionsException = new ExceptionWithCauses("findAnOption(): No options found");

    $possibilities = array(1, 2, 3, 4);
    foreach ($possibilities as $possibility)
    {
        try {
            useOption($possibility);
            return $possibility;
        } catch (Exception $e) {
            $noOptionsException->addCause($e);
        }
    }
    throw $noOptionsException;
}

function useOption($x)
{
    if ($x < 5){
        throw new ExceptionWithCauses("useOption(): $x is too small");
    }
    return $x;
}


And when findAnOption() is called, a exception is thrown with the following message:

findAnOption(): No options found
useOption(): 1 is too small
useOption(): 2 is too small
useOption(): 3 is too small
useOption(): 4 is too small


I'm worried that this is bad practice. I've read that exceptions should only be used in exceptional circumstances. So with that in mind, perhaps I shoul

Solution

The other way you could do this, noting that you don't actually use the return value of useOption, is to have it return an error message or false, along the lines of:

function findAnOption()
{
$problems = array();

$possibilities = array(1, 2, 3, 4);
foreach ($possibilities as $possibility)
{
$problem = useOption($possibility);
if ($problem === false) return $possibility;
$problems[] = $problem;
}
throw new SomeExceptionType($problems);
}

function useOption($x)
{
if ($x

The exception approach can certainly be clearer, and I wouldn't discard it just because it's "using exceptions for control flow". Exceptions are always control flow: the question is whether they're the appropriate one for a given case.

However, I would make one change: I prefer the name
AggregateException (stolen unashamedly from Microsoft's .Net API) to ExceptionWithCauses`.

Context

StackExchange Code Review Q#107862, answer score: 4

Revisions (0)

No revisions yet.