Давно и с удовольствием использую исключения во всех языках, которые их поддерживают и на каких я более менее профессионально программирую. За все это время я выработал один навык использования исключений, от которого до сих пор продолжаю тащиться. Вот что я имею ввиду:
    void func( int i )
    {
        try
        {
        }
        catch( exception_type e )
        {
            throw( exception_type( "func( int i )::" + e.GetErrorMessage() ) );
        }
        catch( ... )
        {
            throw( exception_type( "func( int i )::An undefined error occured" ) );
        }
    }

Затем нам остается в самом верхнем обработчике исключений вывести e.GetMessage() в лог и мы получим на халяву трассировку стека вызовов. В PHP все это выглядит ещё круче:

    function func( $i )
    {
        try
        {
        }
        catch( Exception $e )
        {
            throw( new Exception( "func( $i )::".$e->getMessage() ) );
        }
        catch( ... )
        {
            throw( new Exception( "func( $i )::An undefined error occured" ) );
        }
    }

Фишка в том, что PHP осуществляет подстановку $i во все сообщения об ошибках, поэтому мы получаем не только трассировку вызовов, но и всех параметров, переданных в эти функции. Опять таки нахаляву )).

PS Ссылки по теме:
Организация кода
Open source убьёт мир
Фокусы с наследованием
Стандарты кодирования
Старые парадигмы о главном