Enabling Xdebug’s Exception Handler in Magento
Magento’s default error and exception handlers provide more information than the default php handlers, as they print out a basic backtrace (example) as opposed to just printing out the file and line number of the error but there are many times when Magento’s handlers just don’t cut it; times when you need to see the fully expanded variables that get passed to the functions/methods in the backtrace.
In the Initial Magento Setup Development Tips blog post, I wrote about how Xdebug overrides the default php error handler with a detailed, customizable error backtrace. I explained how to modify Magento’s core code so that php errors get handled by Xdebug, not Magento’s default error handler.
In this blog post, I’m going to explain how to modify Magento so that exceptions get handled by Xdebug, not Magento’s default exception handler.
The Mage::run() method is the method that gets the entire Magento request cycle started, so it makes sense that this is where the exceptions get handled:
/** * Front end main entry point * * @param string $code * @param string $type * @param string|array $options */ public static function run($code = '', $type = 'store', $options=array()) { try { Varien_Profiler::start('mage'); self::setRoot(); self::$_app = new Mage_Core_Model_App(); self::$_events = new Varien_Event_Collection(); self::$_config = new Mage_Core_Model_Config(); self::$_app->run(array( 'scope_code' => $code, 'scope_type' => $type, 'options' => $options, )); Varien_Profiler::stop('mage'); } catch (Mage_Core_Model_Session_Exception $e) { header('Location: ' . self::getBaseUrl()); die(); } catch (Mage_Core_Model_Store_Exception $e) { require_once(self::getBaseDir() . DS . 'errors' . DS . '404.php'); die(); } catch (Exception $e) { if (self::isInstalled() || self::$_isDownloader) { self::printException($e); exit(); } try { self::dispatchEvent('mage_run_exception', array('exception' => $e)); if (!headers_sent()) { header('Location:' . self::getUrl('install')); } else { self::printException($e); } } catch (Exception $ne) { self::printException($ne, $e->getMessage()); } } } |
The problem with the above code is that any exceptions that get thrown by any Magento code get handled by the Mage::printException() method. What we need to do is run the essential code without wrapping it in any try/catch blocks if the developer mode is enabled from the index.php. This will result in all exceptions being handled by the Xdebug exception handler. Here is the resulting code:
/** * Front end main entry point * * @param string $code * @param string $type * @param string|array $options */ public static function run($code = '', $type = 'store', $options=array()) { if(!self::getIsDeveloperMode()){ try { Varien_Profiler::start('mage'); self::setRoot(); self::$_app = new Mage_Core_Model_App(); self::$_events = new Varien_Event_Collection(); self::$_config = new Mage_Core_Model_Config(); self::$_app->run(array( 'scope_code' => $code, 'scope_type' => $type, 'options' => $options, )); Varien_Profiler::stop('mage'); } catch (Mage_Core_Model_Session_Exception $e) { header('Location: ' . self::getBaseUrl()); die(); } catch (Mage_Core_Model_Store_Exception $e) { require_once(self::getBaseDir() . DS . 'errors' . DS . '404.php'); die(); } catch (Exception $e) { if (self::isInstalled() || self::$_isDownloader) { self::printException($e); exit(); } try { self::dispatchEvent('mage_run_exception', array('exception' => $e)); if (!headers_sent()) { header('Location:' . self::getUrl('install')); } else { self::printException($e); } } catch (Exception $ne) { self::printException($ne, $e->getMessage()); } } } else { // If we're running in developer mode, we want all exceptions to be handled by the php|xdebug error handler Varien_Profiler::start('mage'); self::setRoot(); self::$_app = new Mage_Core_Model_App(); self::$_events = new Varien_Event_Collection(); self::$_config = new Mage_Core_Model_Config(); self::$_app->run(array( 'scope_code' => $code, 'scope_type' => $type, 'options' => $options, )); Varien_Profiler::stop('mage'); } } |
This code allows Xdebug’s exception handler to do its magic, resulting in fully detailed exception backtraces like this:
Hopefully this little trick allows you to code Magento more effectively!
This entry was posted on Saturday, May 8th, 2010 at 2:22 pm and is filed under Magento Development. You can follow any responses to this entry through the RSS 2.0 feed. You can leave a response, or trackback from your own site.

May 9th, 2010 at 8:11 pm
once again, a great tip for something that annoys the crap out of me, thanks!
June 9th, 2010 at 8:13 am
<hola>
October 10th, 2010 at 11:49 am
Great tip!
It would be great if future versions of Magento did not define Mage as final. That way you could extend the class to correctly make this modification without modifying the core code.
January 5th, 2012 at 4:30 am
There is no danger in bypassing the magento handler ??