Security update for Core, with self-updated composer
[yaffs-website] / vendor / symfony / debug / ErrorHandler.php
index ae3c2ff8fd24dd2a72f63da993267b1e5e691544..07e0861122a5df9eb4ce6d45eba1389bbe28c120 100644 (file)
@@ -17,6 +17,7 @@ use Symfony\Component\Debug\Exception\ContextErrorException;
 use Symfony\Component\Debug\Exception\FatalErrorException;
 use Symfony\Component\Debug\Exception\FatalThrowableError;
 use Symfony\Component\Debug\Exception\OutOfMemoryException;
+use Symfony\Component\Debug\Exception\SilencedErrorContext;
 use Symfony\Component\Debug\FatalErrorHandler\UndefinedFunctionFatalErrorHandler;
 use Symfony\Component\Debug\FatalErrorHandler\UndefinedMethodFatalErrorHandler;
 use Symfony\Component\Debug\FatalErrorHandler\ClassNotFoundFatalErrorHandler;
@@ -29,7 +30,7 @@ use Symfony\Component\Debug\FatalErrorHandler\FatalErrorHandlerInterface;
  * - thrownErrors: errors thrown as \ErrorException
  * - loggedErrors: logged errors, when not @-silenced
  * - scopedErrors: errors thrown or logged with their local context
- * - tracedErrors: errors logged with their stack trace, only once for repeated errors
+ * - tracedErrors: errors logged with their stack trace
  * - screamedErrors: never @-silenced errors
  *
  * Each error level can be logged by a dedicated PSR-3 logger object.
@@ -43,14 +44,10 @@ use Symfony\Component\Debug\FatalErrorHandler\FatalErrorHandlerInterface;
  * can see them and weight them as more important to fix than others of the same level.
  *
  * @author Nicolas Grekas <p@tchwork.com>
+ * @author GrĂ©goire Pineau <lyrixx@lyrixx.info>
  */
 class ErrorHandler
 {
-    /**
-     * @deprecated since version 2.6, to be removed in 3.0.
-     */
-    const TYPE_DEPRECATION = -100;
-
     private $levels = array(
         E_DEPRECATED => 'Deprecated',
         E_USER_DEPRECATED => 'User Deprecated',
@@ -92,8 +89,8 @@ class ErrorHandler
     private $tracedErrors = 0x77FB; // E_ALL - E_STRICT - E_PARSE
     private $screamedErrors = 0x55; // E_ERROR + E_CORE_ERROR + E_COMPILE_ERROR + E_PARSE
     private $loggedErrors = 0;
+    private $traceReflector;
 
-    private $loggedTraces = array();
     private $isRecursive = 0;
     private $isRoot = false;
     private $exceptionHandler;
@@ -103,38 +100,26 @@ class ErrorHandler
     private static $stackedErrors = array();
     private static $stackedErrorLevels = array();
     private static $toStringException = null;
+    private static $silencedErrorCache = array();
+    private static $silencedErrorCount = 0;
     private static $exitCode = 0;
 
-    /**
-     * Same init value as thrownErrors.
-     *
-     * @deprecated since version 2.6, to be removed in 3.0.
-     */
-    private $displayErrors = 0x1FFF;
-
     /**
      * Registers the error handler.
      *
-     * @param self|null|int $handler The handler to register, or @deprecated (since version 2.6, to be removed in 3.0) bit field of thrown levels
-     * @param bool          $replace Whether to replace or not any existing handler
+     * @param self|null $handler The handler to register
+     * @param bool      $replace Whether to replace or not any existing handler
      *
      * @return self The registered error handler
      */
-    public static function register($handler = null, $replace = true)
+    public static function register(self $handler = null, $replace = true)
     {
         if (null === self::$reservedMemory) {
             self::$reservedMemory = str_repeat('x', 10240);
             register_shutdown_function(__CLASS__.'::handleFatalError');
         }
 
-        $levels = -1;
-
-        if ($handlerIsNew = !$handler instanceof self) {
-            // @deprecated polymorphism, to be removed in 3.0
-            if (null !== $handler) {
-                $levels = $replace ? $handler : 0;
-                $replace = true;
-            }
+        if ($handlerIsNew = null === $handler) {
             $handler = new static();
         }
 
@@ -149,13 +134,27 @@ class ErrorHandler
             $handler = $prev[0];
             $replace = false;
         }
-        if ($replace || !$prev) {
-            $handler->setExceptionHandler(set_exception_handler(array($handler, 'handleException')));
-        } else {
+        if (!$replace && $prev) {
             restore_error_handler();
+            $handlerIsRegistered = is_array($prev) && $handler === $prev[0];
+        } else {
+            $handlerIsRegistered = true;
+        }
+        if (is_array($prev = set_exception_handler(array($handler, 'handleException'))) && $prev[0] instanceof self) {
+            restore_exception_handler();
+            if (!$handlerIsRegistered) {
+                $handler = $prev[0];
+            } elseif ($handler !== $prev[0] && $replace) {
+                set_exception_handler(array($handler, 'handleException'));
+                $p = $prev[0]->setExceptionHandler(null);
+                $handler->setExceptionHandler($p);
+                $prev[0]->setExceptionHandler($p);
+            }
+        } else {
+            $handler->setExceptionHandler($prev);
         }
 
-        $handler->throwAt($levels & $handler->thrownErrors, true);
+        $handler->throwAt(E_ALL & $handler->thrownErrors, true);
 
         return $handler;
     }
@@ -166,6 +165,8 @@ class ErrorHandler
             $this->bootstrappingLogger = $bootstrappingLogger;
             $this->setDefaultLogger($bootstrappingLogger);
         }
+        $this->traceReflector = new \ReflectionProperty('Exception', 'trace');
+        $this->traceReflector->setAccessible(true);
     }
 
     /**
@@ -175,7 +176,7 @@ class ErrorHandler
      * @param array|int       $levels  An array map of E_* to LogLevel::* or an integer bit field of E_* constants
      * @param bool            $replace Whether to replace or not any existing logger
      */
-    public function setDefaultLogger(LoggerInterface $logger, $levels = null, $replace = false)
+    public function setDefaultLogger(LoggerInterface $logger, $levels = E_ALL, $replace = false)
     {
         $loggers = array();
 
@@ -187,7 +188,7 @@ class ErrorHandler
             }
         } else {
             if (null === $levels) {
-                $levels = E_ALL | E_STRICT;
+                $levels = E_ALL;
             }
             foreach ($this->loggers as $type => $log) {
                 if (($type & $levels) && (empty($log[0]) || $replace || $log[0] === $this->bootstrappingLogger)) {
@@ -241,7 +242,7 @@ class ErrorHandler
 
         if ($flush) {
             foreach ($this->bootstrappingLogger->cleanLogs() as $log) {
-                $type = $log[2]['type'];
+                $type = $log[2]['exception'] instanceof \ErrorException ? $log[2]['exception']->getSeverity() : E_ERROR;
                 if (!isset($flush[$type])) {
                     $this->bootstrappingLogger->log($log[0], $log[1], $log[2]);
                 } elseif ($this->loggers[$type][0]) {
@@ -259,14 +260,9 @@ class ErrorHandler
      * @param callable $handler A handler that will be called on Exception
      *
      * @return callable|null The previous exception handler
-     *
-     * @throws \InvalidArgumentException
      */
-    public function setExceptionHandler($handler)
+    public function setExceptionHandler(callable $handler = null)
     {
-        if (null !== $handler && !is_callable($handler)) {
-            throw new \LogicException('The exception handler must be a valid PHP callable.');
-        }
         $prev = $this->exceptionHandler;
         $this->exceptionHandler = $handler;
 
@@ -290,9 +286,6 @@ class ErrorHandler
         }
         $this->reRegister($prev | $this->loggedErrors);
 
-        // $this->displayErrors is @deprecated since version 2.6
-        $this->displayErrors = $this->thrownErrors;
-
         return $prev;
     }
 
@@ -389,6 +382,8 @@ class ErrorHandler
      */
     public function handleError($type, $message, $file, $line)
     {
+        // Level is the current error reporting level to manage silent error.
+        // Strong errors are not authorized to be silenced.
         $level = error_reporting() | E_RECOVERABLE_ERROR | E_USER_ERROR | E_DEPRECATED | E_USER_DEPRECATED;
         $log = $this->loggedErrors & $type;
         $throw = $this->thrownErrors & $type & $level;
@@ -422,28 +417,53 @@ class ErrorHandler
             return true;
         }
 
-        if ($throw) {
-            if (null !== self::$toStringException) {
-                $throw = self::$toStringException;
-                self::$toStringException = null;
-            } elseif ($scope && class_exists('Symfony\Component\Debug\Exception\ContextErrorException')) {
-                // Checking for class existence is a work around for https://bugs.php.net/42098
-                $throw = new ContextErrorException($this->levels[$type].': '.$message, 0, $type, $file, $line, $context);
+        $logMessage = $this->levels[$type].': '.$message;
+
+        if (null !== self::$toStringException) {
+            $errorAsException = self::$toStringException;
+            self::$toStringException = null;
+        } elseif (!$throw && !($type & $level)) {
+            if (!isset(self::$silencedErrorCache[$id = $file.':'.$line])) {
+                $lightTrace = $this->tracedErrors & $type ? $this->cleanTrace(debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS, 3), $type, $file, $line, false) : array();
+                $errorAsException = new SilencedErrorContext($type, $file, $line, $lightTrace);
+            } elseif (isset(self::$silencedErrorCache[$id][$message])) {
+                $lightTrace = null;
+                $errorAsException = self::$silencedErrorCache[$id][$message];
+                ++$errorAsException->count;
             } else {
-                $throw = new \ErrorException($this->levels[$type].': '.$message, 0, $type, $file, $line);
+                $lightTrace = array();
+                $errorAsException = null;
             }
 
-            if (\PHP_VERSION_ID <= 50407 && (\PHP_VERSION_ID >= 50400 || \PHP_VERSION_ID <= 50317)) {
-                // Exceptions thrown from error handlers are sometimes not caught by the exception
-                // handler and shutdown handlers are bypassed before 5.4.8/5.3.18.
-                // We temporarily re-enable display_errors to prevent any blank page related to this bug.
+            if (100 < ++self::$silencedErrorCount) {
+                self::$silencedErrorCache = $lightTrace = array();
+                self::$silencedErrorCount = 1;
+            }
+            if ($errorAsException) {
+                self::$silencedErrorCache[$id][$message] = $errorAsException;
+            }
+            if (null === $lightTrace) {
+                return;
+            }
+        } else {
+            if ($scope) {
+                $errorAsException = new ContextErrorException($logMessage, 0, $type, $file, $line, $context);
+            } else {
+                $errorAsException = new \ErrorException($logMessage, 0, $type, $file, $line);
+            }
 
-                $throw->errorHandlerCanary = new ErrorHandlerCanary();
+            // Clean the trace by removing function arguments and the first frames added by the error handler itself.
+            if ($throw || $this->tracedErrors & $type) {
+                $backtrace = $backtrace ?: $errorAsException->getTrace();
+                $lightTrace = $this->cleanTrace($backtrace, $type, $file, $line, $throw);
+                $this->traceReflector->setValue($errorAsException, $lightTrace);
+            } else {
+                $this->traceReflector->setValue($errorAsException, array());
             }
+        }
 
+        if ($throw) {
             if (E_USER_ERROR & $type) {
-                $backtrace = $backtrace ?: $throw->getTrace();
-
                 for ($i = 1; isset($backtrace[$i]); ++$i) {
                     if (isset($backtrace[$i]['function'], $backtrace[$i]['type'], $backtrace[$i - 1]['function'])
                         && '__toString' === $backtrace[$i]['function']
@@ -462,7 +482,7 @@ class ErrorHandler
                             if (($e instanceof \Exception || $e instanceof \Throwable) && $e->__toString() === $message) {
                                 if (1 === $i) {
                                     // On HHVM
-                                    $throw = $e;
+                                    $errorAsException = $e;
                                     break;
                                 }
                                 self::$toStringException = $e;
@@ -473,7 +493,7 @@ class ErrorHandler
 
                         if (1 < $i) {
                             // On PHP (not on HHVM), display the original error message instead of the default one.
-                            $this->handleException($throw);
+                            $this->handleException($errorAsException);
 
                             // Stop the process by giving back the error to the native handler.
                             return false;
@@ -482,56 +502,25 @@ class ErrorHandler
                 }
             }
 
-            throw $throw;
-        }
-
-        // For duplicated errors, log the trace only once
-        $e = md5("{$type}/{$line}/{$file}\x00{$message}", true);
-        $trace = true;
-
-        if (!($this->tracedErrors & $type) || isset($this->loggedTraces[$e])) {
-            $trace = false;
-        } else {
-            $this->loggedTraces[$e] = 1;
-        }
-
-        $e = compact('type', 'file', 'line', 'level');
-
-        if ($type & $level) {
-            if ($scope) {
-                $e['scope_vars'] = $context;
-                if ($trace) {
-                    $e['stack'] = $backtrace ?: debug_backtrace(DEBUG_BACKTRACE_PROVIDE_OBJECT);
-                }
-            } elseif ($trace) {
-                if (null === $backtrace) {
-                    $e['stack'] = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS);
-                } else {
-                    foreach ($backtrace as &$frame) {
-                        unset($frame['args'], $frame);
-                    }
-                    $e['stack'] = $backtrace;
-                }
-            }
+            throw $errorAsException;
         }
 
         if ($this->isRecursive) {
             $log = 0;
         } elseif (self::$stackedErrorLevels) {
-            self::$stackedErrors[] = array($this->loggers[$type][0], ($type & $level) ? $this->loggers[$type][1] : LogLevel::DEBUG, $message, $e);
+            self::$stackedErrors[] = array(
+                $this->loggers[$type][0],
+                ($type & $level) ? $this->loggers[$type][1] : LogLevel::DEBUG,
+                $logMessage,
+                $errorAsException ? array('exception' => $errorAsException) : array(),
+            );
         } else {
             try {
                 $this->isRecursive = true;
-                $this->loggers[$type][0]->log(($type & $level) ? $this->loggers[$type][1] : LogLevel::DEBUG, $message, $e);
+                $level = ($type & $level) ? $this->loggers[$type][1] : LogLevel::DEBUG;
+                $this->loggers[$type][0]->log($level, $logMessage, $errorAsException ? array('exception' => $errorAsException) : array());
+            } finally {
                 $this->isRecursive = false;
-            } catch (\Exception $e) {
-                $this->isRecursive = false;
-
-                throw $e;
-            } catch (\Throwable $e) {
-                $this->isRecursive = false;
-
-                throw $e;
             }
         }
 
@@ -555,38 +544,29 @@ class ErrorHandler
             $exception = new FatalThrowableError($exception);
         }
         $type = $exception instanceof FatalErrorException ? $exception->getSeverity() : E_ERROR;
+        $handlerException = null;
 
         if (($this->loggedErrors & $type) || $exception instanceof FatalThrowableError) {
-            $e = array(
-                'type' => $type,
-                'file' => $exception->getFile(),
-                'line' => $exception->getLine(),
-                'level' => error_reporting(),
-                'stack' => $exception->getTrace(),
-            );
             if ($exception instanceof FatalErrorException) {
                 if ($exception instanceof FatalThrowableError) {
                     $error = array(
                         'type' => $type,
                         'message' => $message = $exception->getMessage(),
-                        'file' => $e['file'],
-                        'line' => $e['line'],
+                        'file' => $exception->getFile(),
+                        'line' => $exception->getLine(),
                     );
                 } else {
                     $message = 'Fatal '.$exception->getMessage();
                 }
             } elseif ($exception instanceof \ErrorException) {
                 $message = 'Uncaught '.$exception->getMessage();
-                if ($exception instanceof ContextErrorException) {
-                    $e['context'] = $exception->getContext();
-                }
             } else {
                 $message = 'Uncaught Exception: '.$exception->getMessage();
             }
         }
         if ($this->loggedErrors & $type) {
             try {
-                $this->loggers[$type][0]->log($this->loggers[$type][1], $message, $e);
+                $this->loggers[$type][0]->log($this->loggers[$type][1], $message, array('exception' => $exception));
             } catch (\Exception $handlerException) {
             } catch (\Throwable $handlerException) {
             }
@@ -599,18 +579,20 @@ class ErrorHandler
                 }
             }
         }
-        if (empty($this->exceptionHandler)) {
-            throw $exception; // Give back $exception to the native handler
-        }
         try {
-            call_user_func($this->exceptionHandler, $exception);
+            if (null !== $this->exceptionHandler) {
+                return \call_user_func($this->exceptionHandler, $exception);
+            }
+            $handlerException = $handlerException ?: $exception;
         } catch (\Exception $handlerException) {
         } catch (\Throwable $handlerException) {
         }
-        if (isset($handlerException)) {
-            $this->exceptionHandler = null;
-            $this->handleException($handlerException);
+        $this->exceptionHandler = null;
+        if ($exception === $handlerException) {
+            self::$reservedMemory = null; // Disable the fatal error handler
+            throw $exception; // Give back $exception to the native handler
         }
+        $this->handleException($handlerException);
     }
 
     /**
@@ -626,15 +608,39 @@ class ErrorHandler
             return;
         }
 
-        self::$reservedMemory = null;
+        $handler = self::$reservedMemory = null;
+        $handlers = array();
+        $previousHandler = null;
+        $sameHandlerLimit = 10;
 
-        $handler = set_error_handler('var_dump');
-        $handler = is_array($handler) ? $handler[0] : null;
-        restore_error_handler();
+        while (!is_array($handler) || !$handler[0] instanceof self) {
+            $handler = set_exception_handler('var_dump');
+            restore_exception_handler();
 
-        if (!$handler instanceof self) {
+            if (!$handler) {
+                break;
+            }
+            restore_exception_handler();
+
+            if ($handler !== $previousHandler) {
+                array_unshift($handlers, $handler);
+                $previousHandler = $handler;
+            } elseif (0 === --$sameHandlerLimit) {
+                $handler = null;
+                break;
+            }
+        }
+        foreach ($handlers as $h) {
+            set_exception_handler($h);
+        }
+        if (!$handler) {
             return;
         }
+        if ($handler !== $h) {
+            $handler[0]->setExceptionHandler($h);
+        }
+        $handler = $handler[0];
+        $handlers = array();
 
         if ($exit = null === $error) {
             $error = error_get_last();
@@ -687,24 +693,32 @@ class ErrorHandler
      *
      * The most important feature of this is to prevent
      * autoloading until unstackErrors() is called.
+     *
+     * @deprecated since version 3.4, to be removed in 4.0.
      */
     public static function stackErrors()
     {
+        @trigger_error('Support for stacking errors is deprecated since Symfony 3.4 and will be removed in 4.0.', E_USER_DEPRECATED);
+
         self::$stackedErrorLevels[] = error_reporting(error_reporting() | E_PARSE | E_ERROR | E_CORE_ERROR | E_COMPILE_ERROR);
     }
 
     /**
      * Unstacks stacked errors and forwards to the logger.
+     *
+     * @deprecated since version 3.4, to be removed in 4.0.
      */
     public static function unstackErrors()
     {
+        @trigger_error('Support for unstacking errors is deprecated since Symfony 3.4 and will be removed in 4.0.', E_USER_DEPRECATED);
+
         $level = array_pop(self::$stackedErrorLevels);
 
         if (null !== $level) {
-            $e = error_reporting($level);
-            if ($e !== ($level | E_PARSE | E_ERROR | E_CORE_ERROR | E_COMPILE_ERROR)) {
+            $errorReportingLevel = error_reporting($level);
+            if ($errorReportingLevel !== ($level | E_PARSE | E_ERROR | E_CORE_ERROR | E_COMPILE_ERROR)) {
                 // If the user changed the error level, do not overwrite it
-                error_reporting($e);
+                error_reporting($errorReportingLevel);
             }
         }
 
@@ -712,8 +726,8 @@ class ErrorHandler
             $errors = self::$stackedErrors;
             self::$stackedErrors = array();
 
-            foreach ($errors as $e) {
-                $e[0]->log($e[1], $e[2], $e[3]);
+            foreach ($errors as $error) {
+                $error[0]->log($error[1], $error[2], $error[3]);
             }
         }
     }
@@ -734,117 +748,22 @@ class ErrorHandler
         );
     }
 
-    /**
-     * Sets the level at which the conversion to Exception is done.
-     *
-     * @param int|null $level The level (null to use the error_reporting() value and 0 to disable)
-     *
-     * @deprecated since version 2.6, to be removed in 3.0. Use throwAt() instead.
-     */
-    public function setLevel($level)
+    private function cleanTrace($backtrace, $type, $file, $line, $throw)
     {
-        @trigger_error('The '.__METHOD__.' method is deprecated since version 2.6 and will be removed in 3.0. Use the throwAt() method instead.', E_USER_DEPRECATED);
-
-        $level = null === $level ? error_reporting() : $level;
-        $this->throwAt($level, true);
-    }
+        $lightTrace = $backtrace;
 
-    /**
-     * Sets the display_errors flag value.
-     *
-     * @param int $displayErrors The display_errors flag value
-     *
-     * @deprecated since version 2.6, to be removed in 3.0. Use throwAt() instead.
-     */
-    public function setDisplayErrors($displayErrors)
-    {
-        @trigger_error('The '.__METHOD__.' method is deprecated since version 2.6 and will be removed in 3.0. Use the throwAt() method instead.', E_USER_DEPRECATED);
-
-        if ($displayErrors) {
-            $this->throwAt($this->displayErrors, true);
-        } else {
-            $displayErrors = $this->displayErrors;
-            $this->throwAt(0, true);
-            $this->displayErrors = $displayErrors;
-        }
-    }
-
-    /**
-     * Sets a logger for the given channel.
-     *
-     * @param LoggerInterface $logger  A logger interface
-     * @param string          $channel The channel associated with the logger (deprecation, emergency or scream)
-     *
-     * @deprecated since version 2.6, to be removed in 3.0. Use setLoggers() or setDefaultLogger() instead.
-     */
-    public static function setLogger(LoggerInterface $logger, $channel = 'deprecation')
-    {
-        @trigger_error('The '.__METHOD__.' static method is deprecated since version 2.6 and will be removed in 3.0. Use the setLoggers() or setDefaultLogger() methods instead.', E_USER_DEPRECATED);
-
-        $handler = set_error_handler('var_dump');
-        $handler = is_array($handler) ? $handler[0] : null;
-        restore_error_handler();
-        if (!$handler instanceof self) {
-            return;
-        }
-        if ('deprecation' === $channel) {
-            $handler->setDefaultLogger($logger, E_DEPRECATED | E_USER_DEPRECATED, true);
-            $handler->screamAt(E_DEPRECATED | E_USER_DEPRECATED);
-        } elseif ('scream' === $channel) {
-            $handler->setDefaultLogger($logger, E_ALL | E_STRICT, false);
-            $handler->screamAt(E_ALL | E_STRICT);
-        } elseif ('emergency' === $channel) {
-            $handler->setDefaultLogger($logger, E_PARSE | E_ERROR | E_CORE_ERROR | E_COMPILE_ERROR, true);
-            $handler->screamAt(E_PARSE | E_ERROR | E_CORE_ERROR | E_COMPILE_ERROR);
+        for ($i = 0; isset($backtrace[$i]); ++$i) {
+            if (isset($backtrace[$i]['file'], $backtrace[$i]['line']) && $backtrace[$i]['line'] === $line && $backtrace[$i]['file'] === $file) {
+                $lightTrace = array_slice($lightTrace, 1 + $i);
+                break;
+            }
         }
-    }
-
-    /**
-     * @deprecated since version 2.6, to be removed in 3.0. Use handleError() instead.
-     */
-    public function handle($level, $message, $file = 'unknown', $line = 0, $context = array())
-    {
-        $this->handleError(E_USER_DEPRECATED, 'The '.__METHOD__.' method is deprecated since version 2.6 and will be removed in 3.0. Use the handleError() method instead.', __FILE__, __LINE__, array());
-
-        return $this->handleError($level, $message, $file, $line, (array) $context);
-    }
-
-    /**
-     * Handles PHP fatal errors.
-     *
-     * @deprecated since version 2.6, to be removed in 3.0. Use handleFatalError() instead.
-     */
-    public function handleFatal()
-    {
-        @trigger_error('The '.__METHOD__.' method is deprecated since version 2.6 and will be removed in 3.0. Use the handleFatalError() method instead.', E_USER_DEPRECATED);
-
-        static::handleFatalError();
-    }
-}
-
-/**
- * Private class used to work around https://bugs.php.net/54275.
- *
- * @author Nicolas Grekas <p@tchwork.com>
- *
- * @internal
- */
-class ErrorHandlerCanary
-{
-    private static $displayErrors = null;
-
-    public function __construct()
-    {
-        if (null === self::$displayErrors) {
-            self::$displayErrors = ini_set('display_errors', 1);
+        if (!($throw || $this->scopedErrors & $type)) {
+            for ($i = 0; isset($lightTrace[$i]); ++$i) {
+                unset($lightTrace[$i]['args'], $lightTrace[$i]['object']);
+            }
         }
-    }
 
-    public function __destruct()
-    {
-        if (null !== self::$displayErrors) {
-            ini_set('display_errors', self::$displayErrors);
-            self::$displayErrors = null;
-        }
+        return $lightTrace;
     }
 }