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;
-use Symfony\Component\Console\ConsoleEvents;
-use Symfony\Component\Console\Event\ConsoleEvent;
-use Symfony\Component\Console\Output\ConsoleOutputInterface;
/**
* Configures errors and exceptions handlers.
private $throwAt;
private $scream;
private $fileLinkFormat;
+ private $scope;
private $firstCall = true;
+ private $hasTerminatedWithException;
/**
* @param callable|null $exceptionHandler A handler that will be called on Exception
* @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
+ * @param string|array $fileLinkFormat The format for links to source files
+ * @param bool $scope Enables/disables scoping mode
*/
- public function __construct($exceptionHandler, LoggerInterface $logger = null, $levels = null, $throwAt = -1, $scream = true, $fileLinkFormat = null)
+ public function __construct(callable $exceptionHandler = null, LoggerInterface $logger = null, $levels = E_ALL, $throwAt = E_ALL, $scream = true, $fileLinkFormat = null, $scope = true)
{
$this->exceptionHandler = $exceptionHandler;
$this->logger = $logger;
- $this->levels = $levels;
- $this->throwAt = is_numeric($throwAt) ? (int) $throwAt : (null === $throwAt ? null : ($throwAt ? -1 : null));
+ $this->levels = null === $levels ? E_ALL : $levels;
+ $this->throwAt = is_numeric($throwAt) ? (int) $throwAt : (null === $throwAt ? null : ($throwAt ? E_ALL : null));
$this->scream = (bool) $scream;
- $this->fileLinkFormat = $fileLinkFormat ?: ini_get('xdebug.file_link_format') ?: get_cfg_var('xdebug.file_link_format');
+ $this->fileLinkFormat = $fileLinkFormat;
+ $this->scope = (bool) $scope;
}
/**
* Configures the error handler.
- *
- * @param Event|null $event The triggering event
*/
public function configure(Event $event = null)
{
- if (!$this->firstCall) {
+ if (!$event instanceof KernelEvent ? !$this->firstCall : !$event->isMasterRequest()) {
return;
}
- $this->firstCall = false;
+ $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) {
- $handler = set_error_handler('var_dump');
- $handler = is_array($handler) ? $handler[0] : null;
- restore_error_handler();
if ($handler instanceof ErrorHandler) {
if ($this->logger) {
$handler->setDefaultLogger($this->logger, $this->levels);
- if (is_array($this->levels)) {
- $scream = 0;
+ if (\is_array($this->levels)) {
+ $levels = 0;
foreach ($this->levels as $type => $log) {
- $scream |= $type;
+ $levels |= $type;
}
} else {
- $scream = null === $this->levels ? E_ALL | E_STRICT : $this->levels;
+ $levels = $this->levels;
}
if ($this->scream) {
- $handler->screamAt($scream);
+ $handler->screamAt($levels);
+ }
+ if ($this->scope) {
+ $handler->scopeAt($levels & ~E_USER_DEPRECATED & ~E_DEPRECATED);
+ } else {
+ $handler->scopeAt(0, true);
}
$this->logger = $this->levels = null;
}
}
if (!$this->exceptionHandler) {
if ($event instanceof KernelEvent) {
- if (method_exists($event->getKernel(), 'terminateWithException')) {
- $this->exceptionHandler = array($event->getKernel(), 'terminateWithException');
+ 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 ($this->exceptionHandler) {
- $handler = set_exception_handler('var_dump');
- $handler = is_array($handler) ? $handler[0] : null;
- restore_exception_handler();
if ($handler instanceof ErrorHandler) {
- $h = $handler->setExceptionHandler('var_dump') ?: $this->exceptionHandler;
- $handler->setExceptionHandler($h);
- $handler = is_array($h) ? $h[0] : null;
+ $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);
{
$events = array(KernelEvents::REQUEST => array('configure', 2048));
- if (defined('Symfony\Component\Console\ConsoleEvents::COMMAND')) {
+ if ('cli' === \PHP_SAPI && \defined('Symfony\Component\Console\ConsoleEvents::COMMAND')) {
$events[ConsoleEvents::COMMAND] = array('configure', 2048);
}