* * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\HttpKernel\EventListener; use Psr\Log\LoggerInterface; use Symfony\Component\Console\ConsoleEvents; use Symfony\Component\Console\Event\ConsoleEvent; use Symfony\Component\Console\Output\ConsoleOutputInterface; use Symfony\Component\Debug\ErrorHandler; use Symfony\Component\Debug\ExceptionHandler; use Symfony\Component\EventDispatcher\Event; use Symfony\Component\EventDispatcher\EventSubscriberInterface; use Symfony\Component\HttpKernel\Event\KernelEvent; use Symfony\Component\HttpKernel\KernelEvents; /** * Configures errors and exceptions handlers. * * @author Nicolas Grekas */ class DebugHandlersListener implements EventSubscriberInterface { private $exceptionHandler; private $logger; private $levels; private $throwAt; private $scream; private $fileLinkFormat; private $firstCall = true; private $hasTerminatedWithException; /** * @param callable|null $exceptionHandler A handler that will be called on Exception * @param LoggerInterface|null $logger A PSR-3 logger * @param array|int $levels An array map of E_* to LogLevel::* or an integer bit field of E_* constants * @param int|null $throwAt Thrown errors in a bit field of E_* constants, or null to keep the current value * @param bool $scream Enables/disables screaming mode, where even silenced errors are logged * @param string $fileLinkFormat The format for links to source files */ public function __construct($exceptionHandler, LoggerInterface $logger = null, $levels = null, $throwAt = -1, $scream = true, $fileLinkFormat = null) { $this->exceptionHandler = $exceptionHandler; $this->logger = $logger; $this->levels = $levels; $this->throwAt = is_numeric($throwAt) ? (int) $throwAt : (null === $throwAt ? null : ($throwAt ? -1 : null)); $this->scream = (bool) $scream; $this->fileLinkFormat = $fileLinkFormat ?: ini_get('xdebug.file_link_format') ?: get_cfg_var('xdebug.file_link_format'); } /** * Configures the error handler. */ public function configure(Event $event = null) { if (!$event instanceof KernelEvent ? !$this->firstCall : !$event->isMasterRequest()) { return; } $this->firstCall = $this->hasTerminatedWithException = false; $handler = set_exception_handler('var_dump'); $handler = \is_array($handler) ? $handler[0] : null; restore_exception_handler(); if ($this->logger || null !== $this->throwAt) { if ($handler instanceof ErrorHandler) { if ($this->logger) { $handler->setDefaultLogger($this->logger, $this->levels); if (\is_array($this->levels)) { $scream = 0; foreach ($this->levels as $type => $log) { $scream |= $type; } } else { $scream = null === $this->levels ? E_ALL | E_STRICT : $this->levels; } if ($this->scream) { $handler->screamAt($scream); } $this->logger = $this->levels = null; } if (null !== $this->throwAt) { $handler->throwAt($this->throwAt, true); } } } if (!$this->exceptionHandler) { if ($event instanceof KernelEvent) { if (method_exists($kernel = $event->getKernel(), 'terminateWithException')) { $request = $event->getRequest(); $hasRun = &$this->hasTerminatedWithException; $this->exceptionHandler = function (\Exception $e) use ($kernel, $request, &$hasRun) { if ($hasRun) { throw $e; } $hasRun = true; $kernel->terminateWithException($e, $request); }; } } elseif ($event instanceof ConsoleEvent && $app = $event->getCommand()->getApplication()) { $output = $event->getOutput(); if ($output instanceof ConsoleOutputInterface) { $output = $output->getErrorOutput(); } $this->exceptionHandler = function ($e) use ($app, $output) { $app->renderException($e, $output); }; } } if ($this->exceptionHandler) { if ($handler instanceof ErrorHandler) { $h = $handler->setExceptionHandler('var_dump'); if (\is_array($h) && $h[0] instanceof ExceptionHandler) { $handler->setExceptionHandler($h); $handler = $h[0]; } else { $handler->setExceptionHandler($this->exceptionHandler); } } if ($handler instanceof ExceptionHandler) { $handler->setHandler($this->exceptionHandler); if (null !== $this->fileLinkFormat) { $handler->setFileLinkFormat($this->fileLinkFormat); } } $this->exceptionHandler = null; } } public static function getSubscribedEvents() { $events = array(KernelEvents::REQUEST => array('configure', 2048)); if (\defined('Symfony\Component\Console\ConsoleEvents::COMMAND')) { $events[ConsoleEvents::COMMAND] = array('configure', 2048); } return $events; } }