vendor/symfony/http-kernel/EventListener/DebugHandlersListener.php line 76

  1. <?php
  2. /*
  3.  * This file is part of the Symfony package.
  4.  *
  5.  * (c) Fabien Potencier <fabien@symfony.com>
  6.  *
  7.  * For the full copyright and license information, please view the LICENSE
  8.  * file that was distributed with this source code.
  9.  */
  10. namespace Symfony\Component\HttpKernel\EventListener;
  11. use Psr\Log\LoggerInterface;
  12. use Symfony\Component\Console\ConsoleEvents;
  13. use Symfony\Component\Console\Event\ConsoleEvent;
  14. use Symfony\Component\Console\Output\ConsoleOutputInterface;
  15. use Symfony\Component\ErrorHandler\ErrorHandler;
  16. use Symfony\Component\EventDispatcher\EventSubscriberInterface;
  17. use Symfony\Component\HttpKernel\Event\KernelEvent;
  18. use Symfony\Component\HttpKernel\KernelEvents;
  19. /**
  20.  * Sets an exception handler.
  21.  *
  22.  * @author Nicolas Grekas <p@tchwork.com>
  23.  *
  24.  * @final
  25.  *
  26.  * @internal
  27.  */
  28. class DebugHandlersListener implements EventSubscriberInterface
  29. {
  30.     private string|object|null $earlyHandler;
  31.     private ?\Closure $exceptionHandler;
  32.     private bool $webMode;
  33.     private bool $firstCall true;
  34.     private bool $hasTerminatedWithException false;
  35.     /**
  36.      * @param bool          $webMode
  37.      * @param callable|null $exceptionHandler A handler that must support \Throwable instances that will be called on Exception
  38.      */
  39.     public function __construct(?callable $exceptionHandler nullbool|LoggerInterface|null $webMode null)
  40.     {
  41.         if ($webMode instanceof LoggerInterface) {
  42.             // BC with Symfony 5
  43.             $webMode null;
  44.         }
  45.         $handler set_exception_handler('is_int');
  46.         $this->earlyHandler \is_array($handler) ? $handler[0] : null;
  47.         restore_exception_handler();
  48.         $this->exceptionHandler null === $exceptionHandler null $exceptionHandler(...);
  49.         $this->webMode $webMode ?? !\in_array(\PHP_SAPI, ['cli''phpdbg''embed'], true);
  50.     }
  51.     /**
  52.      * Configures the error handler.
  53.      */
  54.     public function configure(?object $event null): void
  55.     {
  56.         if ($event instanceof ConsoleEvent && $this->webMode) {
  57.             return;
  58.         }
  59.         if (!$event instanceof KernelEvent ? !$this->firstCall : !$event->isMainRequest()) {
  60.             return;
  61.         }
  62.         $this->firstCall $this->hasTerminatedWithException false;
  63.         if (!$this->exceptionHandler) {
  64.             if ($event instanceof KernelEvent) {
  65.                 if (method_exists($kernel $event->getKernel(), 'terminateWithException')) {
  66.                     $request $event->getRequest();
  67.                     $hasRun = &$this->hasTerminatedWithException;
  68.                     $this->exceptionHandler = static function (\Throwable $e) use ($kernel$request, &$hasRun) {
  69.                         if ($hasRun) {
  70.                             throw $e;
  71.                         }
  72.                         $hasRun true;
  73.                         $kernel->terminateWithException($e$request);
  74.                     };
  75.                 }
  76.             } elseif ($event instanceof ConsoleEvent && $app $event->getCommand()->getApplication()) {
  77.                 $output $event->getOutput();
  78.                 if ($output instanceof ConsoleOutputInterface) {
  79.                     $output $output->getErrorOutput();
  80.                 }
  81.                 $this->exceptionHandler = static function (\Throwable $e) use ($app$output) {
  82.                     $app->renderThrowable($e$output);
  83.                 };
  84.             }
  85.         }
  86.         if ($this->exceptionHandler) {
  87.             $handler set_exception_handler(static fn () => null);
  88.             $handler \is_array($handler) ? $handler[0] : null;
  89.             restore_exception_handler();
  90.             if (!$handler instanceof ErrorHandler) {
  91.                 $handler $this->earlyHandler;
  92.             }
  93.             if ($handler instanceof ErrorHandler) {
  94.                 $handler->setExceptionHandler($this->exceptionHandler);
  95.             }
  96.             $this->exceptionHandler null;
  97.         }
  98.     }
  99.     public static function getSubscribedEvents(): array
  100.     {
  101.         $events = [KernelEvents::REQUEST => ['configure'2048]];
  102.         if (\defined('Symfony\Component\Console\ConsoleEvents::COMMAND')) {
  103.             $events[ConsoleEvents::COMMAND] = ['configure'2048];
  104.         }
  105.         return $events;
  106.     }
  107. }