How do I forward errors generated in the Bootstrap

2019-06-03 10:16发布

问题:

I am using the default ErrorController that Zend Tool generated for me. The very first thing my index.php file does is to register an error handler that converts errors and warnings into exceptions:

function handleError($errno, $errstr, $errfile, $errline, array $errcontext) {
    // error was suppressed with the @-operator
    if (0 === error_reporting()) {
        return false;
    }

    throw new ErrorException($errstr, 0, $errno, $errfile, $errline);
}

set_error_handler('handleError');

I also have this set up in index.php:

$front = Zend_Controller_Front::getInstance();
$front->throwExceptions(false);

The problem is that it doesn't handle exceptions that come from the Bootstrap file. The exception fires, but the ErrorController doesn't pick it up. Execution of the page simply halts and no views are rendered.

How can I route every exception and warning through the error controller (with the exception of syntax and fatal errors, of course)?

回答1:

If an Exception occurs in the Bootstrap then it cannot be passed to the ErrorController because your application has not been set up yet so it has no idea about the ErrorController yet.

You'll have to use something else to handle it.

Having an application which is highly likely to throw an uncaught Exception in the Bootstrap is surely not a good thing. You should catch the Exceptions that occur in the Bootstrap and handle them accordingly.



回答2:

But if you connect to the database JIT (Just In Time), there should be no problem. You can actually move the database connection after bootstrap using Front Controller plugins. The DB connection setup can be at _dispatchLoopStartup() if you don't need it to setup other things (like routes, some pre-dispatch translations, etc).

//in bootstrap
$front->registerPlugin(new Awesome_Db_Plugin($zendConfigWithDbOptions));
// in plugin (options injected via constructor to private member
public function dispatchLoopStartup() {
    $db = Zend_Db::factory($this->_options);
    Zend_Registry::set('db', $db);
}

This way every exception thrown during the db connection will be fired after $front->dispatch();



回答3:

this is from my index.php, may be it'll be useful:

//bootstrap, and run application
try {
    require_once 'Zend/Application.php';
    //create application and configure it.
    $application = new Zend_Application(
        getenv('APPLICATION_ENV') ? getenv('APPLICATION_ENV') : 'production',
        array('config' => array(APPLICATION_PATH . DS . 'configs' . DS . 'application.ini'))
    );
    //run application
    $application->bootstrap()->run();
} catch (Exception $e) {
    //fallback for uncatched exceptions
    ob_clean();
    //ensure error will be logged and firephp backend, if enabled, will send log messages
    if(is_object($application)
        && $application->bootstrap('log')
        && Zend_Registry::isRegistered('Zend_Log')
    ) {
        Zend_Registry::get('Zend_Log')
            ->log($e,Zend_Log::CRIT);
    }
    $wildfire = Zend_Wildfire_Channel_HttpHeaders::getInstance();
    if(!($response = Zend_Controller_Front::getInstance()->getResponse())) {
        $response = new Zend_Controller_Response_Http();
        $wildfire->setRequest(new Zend_Controller_Request_Http());
        $wildfire->setResponse($response);
    }
    if($response->canSendHeaders()) {
        $response->clearHeaders();
        $response->setHttpResponseCode(500);
        $wildfire->flush();
        $response->sendResponse();
    }
    //put static html for error page here
    echo 'Startup error occured. Try again later';
}

note: Zend_Registry::isRegistered('Zend_Log') Zend_Log instance registered with registry in my extended application resource