Podcast #128: We chat with Kent C Dodds about why he loves React and discuss what life was like in the dark days before Git. Listen now.
2 of 2 Reworded several paragraphs to help clarity and fixed spelling errors

I would argue it's impossible to handle all exceptions the same way. I think you should let it propagate back to the calling code as only that ultimately knows how to handle the exceptional situation.

As an example imagine you have an blog. Every hour you query the database for new articles to populate a cache. But luck isn't with you and the database is temporarily unavailable. You could let the exception go unhandled and the whole site is down. You could also handle the exception inside the database abstraction layer and return a default result (effectively hiding the exception). But returning a default value would overwrite the cache with nothing. The site is up, but doesn't work properly. You could also log the error, rethrow the exception to let the calling code decide what to do. The calling code could reuse the already cached query results and extend the lifetime of the cache another hour hoping for the database to come back up. This way your users would experience minimal disruption of your site and may never even notice you had problems.

But it isn't always easy to determine what to do in exceptional cases and sometimes it would preferable to just let the exception bubble up until it hits a generic exception handler, which displays a generic error page. You can in addition implement some general procedures if a query fails, such as error logging in this generic exception handler. This would be preferable as this can be considered boilerplate code that doesn't change anything. And having unhandled exceptions emailed to you (as an example) lets you resolve the issue faster than if you were to discover the issue yourself.

You also get an additional bonus by grouping generic-logging code in a single place. You can handle specific logging alongside relevant code (where details are available) and if your generic logging procedure should change you only need to change it once.

Using your fetchAll() method the structure could look like:

public function fetchAll($sql, $bind = array()) {

    // Do something awesome before try-catch block.

    try {

        // Execute query...

    }catch(PDOException $exception) {

        $this->logger->log('SQL query failed: ' . $exception->getMessage());

         * Re-throw the exception to let the calling code
         * handle the situation.
        throw $exception


    // Continue as everything executed as expected.