Throw an exception which contains a nested set of previous exceptions
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 &lt; 5) {
        return "useOption(): $x is too small";
    }

    // No problems
    return false;
}


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.