mirror of
https://github.com/symfony/debug.git
synced 2026-03-25 17:52:07 +01:00
Compare commits
76 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e90099a295 | ||
|
|
3b77268009 | ||
|
|
0d4887956a | ||
|
|
4a99c3a6ca | ||
|
|
4f9612ed86 | ||
|
|
0ccbc5c4ca | ||
|
|
b58c5193eb | ||
|
|
bdc57ddfb5 | ||
|
|
a4bf3f9ca9 | ||
|
|
637babfcdc | ||
|
|
567681e2c4 | ||
|
|
b3bdc191eb | ||
|
|
84a966b619 | ||
|
|
2f9a68243d | ||
|
|
3717db3bfa | ||
|
|
62a045d4cc | ||
|
|
0c4933bda1 | ||
|
|
83059abb7c | ||
|
|
49dea9f77d | ||
|
|
e17648a194 | ||
|
|
9544c5518f | ||
|
|
62a68f6404 | ||
|
|
a9844f3cd2 | ||
|
|
0a8d55717a | ||
|
|
d99867cf7b | ||
|
|
6945a0d019 | ||
|
|
8c29235936 | ||
|
|
659f346c4a | ||
|
|
316b203b51 | ||
|
|
aec192ddd4 | ||
|
|
6041920341 | ||
|
|
a3a850315e | ||
|
|
f7c5256f43 | ||
|
|
31106b58d5 | ||
|
|
bec6ab977e | ||
|
|
13ebf897a8 | ||
|
|
2477199ad1 | ||
|
|
d9e18587ad | ||
|
|
c7d6d8a599 | ||
|
|
00f654c530 | ||
|
|
2a1b327f5f | ||
|
|
dfaa39d719 | ||
|
|
d8009e5ad7 | ||
|
|
5fe2066e79 | ||
|
|
40bc3196e1 | ||
|
|
3b97c83b47 | ||
|
|
056d028521 | ||
|
|
ef78aaaa3e | ||
|
|
a6d49c84a0 | ||
|
|
8dc1218161 | ||
|
|
d251523f4e | ||
|
|
f2e4849892 | ||
|
|
a6f7b78e40 | ||
|
|
d2367812b2 | ||
|
|
26527ccf6f | ||
|
|
9233292b81 | ||
|
|
8e255a0c55 | ||
|
|
e96f1ff28e | ||
|
|
574f6fed54 | ||
|
|
ef9b1c139e | ||
|
|
142588bc7e | ||
|
|
9878d595ce | ||
|
|
9044cdf657 | ||
|
|
386364a0e7 | ||
|
|
5aca4aa960 | ||
|
|
2673677356 | ||
|
|
08688bae7a | ||
|
|
a1de6b7d67 | ||
|
|
b5b13b1909 | ||
|
|
7cca5bb1b1 | ||
|
|
3b3484aed6 | ||
|
|
8446878685 | ||
|
|
08589346bd | ||
|
|
2d9eb3ddb3 | ||
|
|
5f109a38d2 | ||
|
|
d0ee40c1e2 |
@@ -1,11 +1,6 @@
|
||||
CHANGELOG
|
||||
=========
|
||||
|
||||
3.0.0
|
||||
-----
|
||||
|
||||
* removed classes, methods and interfaces deprecated in 2.x
|
||||
|
||||
2.8.0
|
||||
-----
|
||||
|
||||
|
||||
@@ -31,7 +31,7 @@ class Debug
|
||||
* @param int $errorReportingLevel The level of error reporting you want
|
||||
* @param bool $displayErrors Whether to display errors (for development) or just log them (for production)
|
||||
*/
|
||||
public static function enable($errorReportingLevel = E_ALL, $displayErrors = true)
|
||||
public static function enable($errorReportingLevel = null, $displayErrors = true)
|
||||
{
|
||||
if (static::$enabled) {
|
||||
return;
|
||||
@@ -42,10 +42,10 @@ class Debug
|
||||
if (null !== $errorReportingLevel) {
|
||||
error_reporting($errorReportingLevel);
|
||||
} else {
|
||||
error_reporting(E_ALL);
|
||||
error_reporting(-1);
|
||||
}
|
||||
|
||||
if ('cli' !== php_sapi_name()) {
|
||||
if ('cli' !== PHP_SAPI) {
|
||||
ini_set('display_errors', 0);
|
||||
ExceptionHandler::register();
|
||||
} elseif ($displayErrors && (!ini_get('log_errors') || ini_get('error_log'))) {
|
||||
|
||||
@@ -26,6 +26,7 @@ class DebugClassLoader
|
||||
{
|
||||
private $classLoader;
|
||||
private $isFinder;
|
||||
private $wasFinder;
|
||||
private static $caseCheck;
|
||||
private static $deprecated = array();
|
||||
private static $php7Reserved = array('int', 'float', 'bool', 'string', 'true', 'false', 'null');
|
||||
@@ -34,26 +35,53 @@ class DebugClassLoader
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param callable $classLoader A class loader
|
||||
* @param callable|object $classLoader Passing an object is @deprecated since version 2.5 and support for it will be removed in 3.0
|
||||
*/
|
||||
public function __construct(callable $classLoader)
|
||||
public function __construct($classLoader)
|
||||
{
|
||||
$this->classLoader = $classLoader;
|
||||
$this->isFinder = is_array($classLoader) && method_exists($classLoader[0], 'findFile');
|
||||
$this->wasFinder = is_object($classLoader) && method_exists($classLoader, 'findFile');
|
||||
|
||||
if ($this->wasFinder) {
|
||||
@trigger_error('The '.__METHOD__.' method will no longer support receiving an object into its $classLoader argument in 3.0.', E_USER_DEPRECATED);
|
||||
$this->classLoader = array($classLoader, 'loadClass');
|
||||
$this->isFinder = true;
|
||||
} else {
|
||||
$this->classLoader = $classLoader;
|
||||
$this->isFinder = is_array($classLoader) && method_exists($classLoader[0], 'findFile');
|
||||
}
|
||||
|
||||
if (!isset(self::$caseCheck)) {
|
||||
self::$caseCheck = false !== stripos(PHP_OS, 'win') ? (false !== stripos(PHP_OS, 'darwin') ? 2 : 1) : 0;
|
||||
$file = file_exists(__FILE__) ? __FILE__ : rtrim(realpath('.'), DIRECTORY_SEPARATOR);
|
||||
$i = strrpos($file, DIRECTORY_SEPARATOR);
|
||||
$dir = substr($file, 0, 1 + $i);
|
||||
$file = substr($file, 1 + $i);
|
||||
$test = strtoupper($file) === $file ? strtolower($file) : strtoupper($file);
|
||||
$test = realpath($dir.$test);
|
||||
|
||||
if (false === $test || false === $i) {
|
||||
// filesystem is case sensitive
|
||||
self::$caseCheck = 0;
|
||||
} elseif (substr($test, -strlen($file)) === $file) {
|
||||
// filesystem is case insensitive and realpath() normalizes the case of characters
|
||||
self::$caseCheck = 1;
|
||||
} elseif (false !== stripos(PHP_OS, 'darwin')) {
|
||||
// on MacOSX, HFS+ is case insensitive but realpath() doesn't normalize the case of characters
|
||||
self::$caseCheck = 2;
|
||||
} else {
|
||||
// filesystem case checks failed, fallback to disabling them
|
||||
self::$caseCheck = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the wrapped class loader.
|
||||
*
|
||||
* @return callable The wrapped class loader
|
||||
* @return callable|object A class loader. Since version 2.5, returning an object is @deprecated and support for it will be removed in 3.0
|
||||
*/
|
||||
public function getClassLoader()
|
||||
{
|
||||
return $this->classLoader;
|
||||
return $this->wasFinder ? $this->classLoader[0] : $this->classLoader;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -104,6 +132,24 @@ class DebugClassLoader
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds a file by class name.
|
||||
*
|
||||
* @param string $class A class name to resolve to file
|
||||
*
|
||||
* @return string|null
|
||||
*
|
||||
* @deprecated since version 2.5, to be removed in 3.0.
|
||||
*/
|
||||
public function findFile($class)
|
||||
{
|
||||
@trigger_error('The '.__METHOD__.' method is deprecated since version 2.5 and will be removed in 3.0.', E_USER_DEPRECATED);
|
||||
|
||||
if ($this->wasFinder) {
|
||||
return $this->classLoader[0]->findFile($class);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads the given class or interface.
|
||||
*
|
||||
@@ -126,11 +172,19 @@ class DebugClassLoader
|
||||
call_user_func($this->classLoader, $class);
|
||||
$file = false;
|
||||
}
|
||||
} finally {
|
||||
} catch (\Exception $e) {
|
||||
ErrorHandler::unstackErrors();
|
||||
|
||||
throw $e;
|
||||
} catch (\Throwable $e) {
|
||||
ErrorHandler::unstackErrors();
|
||||
|
||||
throw $e;
|
||||
}
|
||||
|
||||
$exists = class_exists($class, false) || interface_exists($class, false) || trait_exists($class, false);
|
||||
ErrorHandler::unstackErrors();
|
||||
|
||||
$exists = class_exists($class, false) || interface_exists($class, false) || (function_exists('trait_exists') && trait_exists($class, false));
|
||||
|
||||
if ('\\' === $class[0]) {
|
||||
$class = substr($class, 1);
|
||||
@@ -162,15 +216,32 @@ class DebugClassLoader
|
||||
break;
|
||||
}
|
||||
}
|
||||
$parent = $refl->getParentClass();
|
||||
$parent = get_parent_class($class);
|
||||
|
||||
if (!$parent || strncmp($ns, $parent->name, $len)) {
|
||||
if ($parent && isset(self::$deprecated[$parent->name]) && strncmp($ns, $parent->name, $len)) {
|
||||
@trigger_error(sprintf('The %s class extends %s that is deprecated %s', $name, $parent->name, self::$deprecated[$parent->name]), E_USER_DEPRECATED);
|
||||
if (!$parent || strncmp($ns, $parent, $len)) {
|
||||
if ($parent && isset(self::$deprecated[$parent]) && strncmp($ns, $parent, $len)) {
|
||||
@trigger_error(sprintf('The %s class extends %s that is deprecated %s', $name, $parent, self::$deprecated[$parent]), E_USER_DEPRECATED);
|
||||
}
|
||||
|
||||
$parentInterfaces = array();
|
||||
$deprecatedInterfaces = array();
|
||||
if ($parent) {
|
||||
foreach (class_implements($parent) as $interface) {
|
||||
$parentInterfaces[$interface] = 1;
|
||||
}
|
||||
}
|
||||
|
||||
foreach ($refl->getInterfaceNames() as $interface) {
|
||||
if (isset(self::$deprecated[$interface]) && strncmp($ns, $interface, $len) && !($parent && $parent->implementsInterface($interface))) {
|
||||
if (isset(self::$deprecated[$interface]) && strncmp($ns, $interface, $len)) {
|
||||
$deprecatedInterfaces[] = $interface;
|
||||
}
|
||||
foreach (class_implements($interface) as $interface) {
|
||||
$parentInterfaces[$interface] = 1;
|
||||
}
|
||||
}
|
||||
|
||||
foreach ($deprecatedInterfaces as $interface) {
|
||||
if (!isset($parentInterfaces[$interface])) {
|
||||
@trigger_error(sprintf('The %s %s %s that is deprecated %s', $name, $refl->isInterface() ? 'interface extends' : 'class implements', $interface, self::$deprecated[$interface]), E_USER_DEPRECATED);
|
||||
}
|
||||
}
|
||||
@@ -193,7 +264,7 @@ class DebugClassLoader
|
||||
$i = count($tail) - 1;
|
||||
$j = count($real) - 1;
|
||||
|
||||
while (isset($tail[$i], $real[$j]) && $tail[$i] === $real[$j]) {
|
||||
while (isset($tail[$i], $real[$j]) && $tail[$i] === $real[$j]) {
|
||||
--$i;
|
||||
--$j;
|
||||
}
|
||||
|
||||
232
ErrorHandler.php
232
ErrorHandler.php
@@ -46,6 +46,11 @@ use Symfony\Component\Debug\FatalErrorHandler\FatalErrorHandlerInterface;
|
||||
*/
|
||||
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',
|
||||
@@ -90,6 +95,7 @@ class ErrorHandler
|
||||
|
||||
private $loggedTraces = array();
|
||||
private $isRecursive = 0;
|
||||
private $isRoot = false;
|
||||
private $exceptionHandler;
|
||||
private $bootstrappingLogger;
|
||||
|
||||
@@ -98,26 +104,45 @@ class ErrorHandler
|
||||
private static $stackedErrorLevels = array();
|
||||
private static $toStringException = null;
|
||||
|
||||
/**
|
||||
* 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 $handler The handler to register
|
||||
* @param bool $replace Whether to replace or not any existing 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
|
||||
*
|
||||
* @return self The registered error handler
|
||||
*/
|
||||
public static function register(self $handler = null, $replace = true)
|
||||
public static function register($handler = null, $replace = true)
|
||||
{
|
||||
if (null === self::$reservedMemory) {
|
||||
self::$reservedMemory = str_repeat('x', 10240);
|
||||
register_shutdown_function(__CLASS__.'::handleFatalError');
|
||||
}
|
||||
|
||||
if ($handlerIsNew = null === $handler) {
|
||||
$levels = -1;
|
||||
|
||||
if ($handlerIsNew = !$handler instanceof self) {
|
||||
// @deprecated polymorphism, to be removed in 3.0
|
||||
if (null !== $handler) {
|
||||
$levels = $replace ? $handler : 0;
|
||||
$replace = true;
|
||||
}
|
||||
$handler = new static();
|
||||
}
|
||||
|
||||
$prev = set_error_handler(array($handler, 'handleError'), $handler->thrownErrors | $handler->loggedErrors);
|
||||
if (null === $prev = set_error_handler(array($handler, 'handleError'))) {
|
||||
restore_error_handler();
|
||||
// Specifying the error types earlier would expose us to https://bugs.php.net/63206
|
||||
set_error_handler(array($handler, 'handleError'), $handler->thrownErrors | $handler->loggedErrors);
|
||||
$handler->isRoot = true;
|
||||
}
|
||||
|
||||
if ($handlerIsNew && is_array($prev) && $prev[0] instanceof self) {
|
||||
$handler = $prev[0];
|
||||
@@ -129,7 +154,7 @@ class ErrorHandler
|
||||
restore_error_handler();
|
||||
}
|
||||
|
||||
$handler->throwAt(E_ALL & $handler->thrownErrors, true);
|
||||
$handler->throwAt($levels & $handler->thrownErrors, true);
|
||||
|
||||
return $handler;
|
||||
}
|
||||
@@ -149,7 +174,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 = E_ALL, $replace = false)
|
||||
public function setDefaultLogger(LoggerInterface $logger, $levels = null, $replace = false)
|
||||
{
|
||||
$loggers = array();
|
||||
|
||||
@@ -161,7 +186,7 @@ class ErrorHandler
|
||||
}
|
||||
} else {
|
||||
if (null === $levels) {
|
||||
$levels = E_ALL;
|
||||
$levels = E_ALL | E_STRICT;
|
||||
}
|
||||
foreach ($this->loggers as $type => $log) {
|
||||
if (($type & $levels) && (empty($log[0]) || $replace || $log[0] === $this->bootstrappingLogger)) {
|
||||
@@ -233,9 +258,14 @@ 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(callable $handler = null)
|
||||
public function setExceptionHandler($handler)
|
||||
{
|
||||
if (null !== $handler && !is_callable($handler)) {
|
||||
throw new \LogicException('The exception handler must be a valid PHP callable.');
|
||||
}
|
||||
$prev = $this->exceptionHandler;
|
||||
$this->exceptionHandler = $handler;
|
||||
|
||||
@@ -253,12 +283,15 @@ class ErrorHandler
|
||||
public function throwAt($levels, $replace = false)
|
||||
{
|
||||
$prev = $this->thrownErrors;
|
||||
$this->thrownErrors = E_ALL & ($levels | E_RECOVERABLE_ERROR | E_USER_ERROR) & ~E_USER_DEPRECATED & ~E_DEPRECATED;
|
||||
$this->thrownErrors = ($levels | E_RECOVERABLE_ERROR | E_USER_ERROR) & ~E_USER_DEPRECATED & ~E_DEPRECATED;
|
||||
if (!$replace) {
|
||||
$this->thrownErrors |= $prev;
|
||||
}
|
||||
$this->reRegister($prev | $this->loggedErrors);
|
||||
|
||||
// $this->displayErrors is @deprecated since version 2.6
|
||||
$this->displayErrors = $this->thrownErrors;
|
||||
|
||||
return $prev;
|
||||
}
|
||||
|
||||
@@ -325,12 +358,16 @@ class ErrorHandler
|
||||
private function reRegister($prev)
|
||||
{
|
||||
if ($prev !== $this->thrownErrors | $this->loggedErrors) {
|
||||
$handler = set_error_handler('var_dump', 0);
|
||||
$handler = set_error_handler('var_dump');
|
||||
$handler = is_array($handler) ? $handler[0] : null;
|
||||
restore_error_handler();
|
||||
if ($handler === $this) {
|
||||
restore_error_handler();
|
||||
set_error_handler(array($this, 'handleError'), $this->thrownErrors | $this->loggedErrors);
|
||||
if ($this->isRoot) {
|
||||
set_error_handler(array($this, 'handleError'), $this->thrownErrors | $this->loggedErrors);
|
||||
} else {
|
||||
set_error_handler(array($this, 'handleError'));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -339,17 +376,17 @@ class ErrorHandler
|
||||
* Handles errors by filtering then logging them according to the configured bit fields.
|
||||
*
|
||||
* @param int $type One of the E_* constants
|
||||
* @param string $message
|
||||
* @param string $file
|
||||
* @param int $line
|
||||
* @param array $context
|
||||
*
|
||||
* @return bool Returns false when no handling happens so that the PHP engine can handle the error itself.
|
||||
* @return bool Returns false when no handling happens so that the PHP engine can handle the error itself
|
||||
*
|
||||
* @throws \ErrorException When $this->thrownErrors requests so
|
||||
*
|
||||
* @internal
|
||||
*/
|
||||
public function handleError($type, $message, $file, $line, array $context, array $backtrace = null)
|
||||
public function handleError($type, $message, $file, $line)
|
||||
{
|
||||
$level = error_reporting() | E_RECOVERABLE_ERROR | E_USER_ERROR | E_DEPRECATED | E_USER_DEPRECATED;
|
||||
$log = $this->loggedErrors & $type;
|
||||
@@ -359,6 +396,21 @@ class ErrorHandler
|
||||
if (!$type || (!$log && !$throw)) {
|
||||
return $type && $log;
|
||||
}
|
||||
$scope = $this->scopedErrors & $type;
|
||||
|
||||
if (4 < $numArgs = func_num_args()) {
|
||||
$context = $scope ? (func_get_arg(4) ?: array()) : array();
|
||||
$backtrace = 5 < $numArgs ? func_get_arg(5) : null; // defined on HHVM
|
||||
} else {
|
||||
$context = array();
|
||||
$backtrace = null;
|
||||
}
|
||||
|
||||
if (isset($context['GLOBALS']) && $scope) {
|
||||
$e = $context; // Whatever the signature of the method,
|
||||
unset($e['GLOBALS'], $context); // $context is always a reference in 5.3
|
||||
$context = $e;
|
||||
}
|
||||
|
||||
if (null !== $backtrace && $type & E_ERROR) {
|
||||
// E_ERROR fatal errors are triggered on HHVM when
|
||||
@@ -373,12 +425,21 @@ class ErrorHandler
|
||||
if (null !== self::$toStringException) {
|
||||
$throw = self::$toStringException;
|
||||
self::$toStringException = null;
|
||||
} elseif (($this->scopedErrors & $type) && class_exists(ContextErrorException::class)) {
|
||||
} 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);
|
||||
} else {
|
||||
$throw = new \ErrorException($this->levels[$type].': '.$message, 0, $type, $file, $line);
|
||||
}
|
||||
|
||||
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.
|
||||
|
||||
$throw->errorHandlerCanary = new ErrorHandlerCanary();
|
||||
}
|
||||
|
||||
if (E_USER_ERROR & $type) {
|
||||
$backtrace = $backtrace ?: $throw->getTrace();
|
||||
|
||||
@@ -436,7 +497,7 @@ class ErrorHandler
|
||||
$e = compact('type', 'file', 'line', 'level');
|
||||
|
||||
if ($type & $level) {
|
||||
if ($this->scopedErrors & $type) {
|
||||
if ($scope) {
|
||||
$e['scope_vars'] = $context;
|
||||
if ($trace) {
|
||||
$e['stack'] = $backtrace ?: debug_backtrace(DEBUG_BACKTRACE_PROVIDE_OBJECT);
|
||||
@@ -461,8 +522,15 @@ class ErrorHandler
|
||||
try {
|
||||
$this->isRecursive = true;
|
||||
$this->loggers[$type][0]->log(($type & $level) ? $this->loggers[$type][1] : LogLevel::DEBUG, $message, $e);
|
||||
} finally {
|
||||
$this->isRecursive = false;
|
||||
} catch (\Exception $e) {
|
||||
$this->isRecursive = false;
|
||||
|
||||
throw $e;
|
||||
} catch (\Throwable $e) {
|
||||
$this->isRecursive = false;
|
||||
|
||||
throw $e;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -484,7 +552,7 @@ class ErrorHandler
|
||||
}
|
||||
$type = $exception instanceof FatalErrorException ? $exception->getSeverity() : E_ERROR;
|
||||
|
||||
if ($this->loggedErrors & $type) {
|
||||
if (($this->loggedErrors & $type) || $exception instanceof FatalThrowableError) {
|
||||
$e = array(
|
||||
'type' => $type,
|
||||
'file' => $exception->getFile(),
|
||||
@@ -511,8 +579,12 @@ class ErrorHandler
|
||||
} else {
|
||||
$message = 'Uncaught Exception: '.$exception->getMessage();
|
||||
}
|
||||
if ($this->loggedErrors & $e['type']) {
|
||||
$this->loggers[$e['type']][0]->log($this->loggers[$e['type']][1], $message, $e);
|
||||
}
|
||||
if ($this->loggedErrors & $type) {
|
||||
try {
|
||||
$this->loggers[$type][0]->log($this->loggers[$type][1], $message, $e);
|
||||
} catch (\Exception $handlerException) {
|
||||
} catch (\Throwable $handlerException) {
|
||||
}
|
||||
}
|
||||
if ($exception instanceof FatalErrorException && !$exception instanceof OutOfMemoryException && $error) {
|
||||
@@ -552,7 +624,7 @@ class ErrorHandler
|
||||
|
||||
self::$reservedMemory = null;
|
||||
|
||||
$handler = set_error_handler('var_dump', 0);
|
||||
$handler = set_error_handler('var_dump');
|
||||
$handler = is_array($handler) ? $handler[0] : null;
|
||||
restore_error_handler();
|
||||
|
||||
@@ -570,6 +642,8 @@ class ErrorHandler
|
||||
}
|
||||
} catch (\Exception $exception) {
|
||||
// Handled below
|
||||
} catch (\Throwable $exception) {
|
||||
// Handled below
|
||||
}
|
||||
|
||||
if ($error && $error['type'] &= E_PARSE | E_ERROR | E_CORE_ERROR | E_COMPILE_ERROR) {
|
||||
@@ -649,4 +723,118 @@ class ErrorHandler
|
||||
new ClassNotFoundFatalErrorHandler(),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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)
|
||||
{
|
||||
@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);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @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);
|
||||
}
|
||||
}
|
||||
|
||||
public function __destruct()
|
||||
{
|
||||
if (null !== self::$displayErrors) {
|
||||
ini_set('display_errors', self::$displayErrors);
|
||||
self::$displayErrors = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
23
Exception/DummyException.php
Normal file
23
Exception/DummyException.php
Normal file
@@ -0,0 +1,23 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\Debug\Exception;
|
||||
|
||||
@trigger_error('The '.__NAMESPACE__.'\DummyException class is deprecated since version 2.5 and will be removed in 3.0.', E_USER_DEPRECATED);
|
||||
|
||||
/**
|
||||
* @author Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* @deprecated since version 2.5, to be removed in 3.0.
|
||||
*/
|
||||
class DummyException extends \ErrorException
|
||||
{
|
||||
}
|
||||
@@ -9,14 +9,31 @@
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\HttpKernel\Exception;
|
||||
|
||||
/**
|
||||
* Fatal Error Exception.
|
||||
*
|
||||
* @author Fabien Potencier <fabien@symfony.com>
|
||||
* @author Konstanton Myakshin <koc-dp@yandex.ru>
|
||||
* @author Nicolas Grekas <p@tchwork.com>
|
||||
*
|
||||
* @deprecated Deprecated in 2.3, to be removed in 3.0. Use the same class from the Debug component instead.
|
||||
*/
|
||||
class FatalErrorException extends \ErrorException
|
||||
{
|
||||
}
|
||||
|
||||
namespace Symfony\Component\Debug\Exception;
|
||||
|
||||
use Symfony\Component\HttpKernel\Exception\FatalErrorException as LegacyFatalErrorException;
|
||||
|
||||
/**
|
||||
* Fatal Error Exception.
|
||||
*
|
||||
* @author Konstanton Myakshin <koc-dp@yandex.ru>
|
||||
*/
|
||||
class FatalErrorException extends \ErrorException
|
||||
class FatalErrorException extends LegacyFatalErrorException
|
||||
{
|
||||
public function __construct($message, $code, $severity, $filename, $lineno, $traceOffset = null, $traceArgs = true, array $trace = null)
|
||||
{
|
||||
|
||||
@@ -27,7 +27,7 @@ class FatalThrowableError extends FatalErrorException
|
||||
$message = 'Type error: '.$e->getMessage();
|
||||
$severity = E_RECOVERABLE_ERROR;
|
||||
} else {
|
||||
$message = 'Fatal error: '.$e->getMessage();
|
||||
$message = $e->getMessage();
|
||||
$severity = E_ERROR;
|
||||
}
|
||||
|
||||
|
||||
@@ -9,8 +9,49 @@
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\HttpKernel\Exception;
|
||||
|
||||
use Symfony\Component\Debug\Exception\FlattenException as DebugFlattenException;
|
||||
|
||||
/**
|
||||
* FlattenException wraps a PHP Exception to be able to serialize it.
|
||||
*
|
||||
* Basically, this class removes all objects from the trace.
|
||||
*
|
||||
* @author Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* @deprecated Deprecated in 2.3, to be removed in 3.0. Use the same class from the Debug component instead.
|
||||
*/
|
||||
class FlattenException
|
||||
{
|
||||
private $handler;
|
||||
|
||||
public static function __callStatic($method, $args)
|
||||
{
|
||||
if (!method_exists('Symfony\Component\Debug\Exception\FlattenException', $method)) {
|
||||
throw new \BadMethodCallException(sprintf('Call to undefined method %s::%s()', get_called_class(), $method));
|
||||
}
|
||||
|
||||
return call_user_func_array(array('Symfony\Component\Debug\Exception\FlattenException', $method), $args);
|
||||
}
|
||||
|
||||
public function __call($method, $args)
|
||||
{
|
||||
if (!isset($this->handler)) {
|
||||
$this->handler = new DebugFlattenException();
|
||||
}
|
||||
|
||||
if (!method_exists($this->handler, $method)) {
|
||||
throw new \BadMethodCallException(sprintf('Call to undefined method %s::%s()', get_class($this), $method));
|
||||
}
|
||||
|
||||
return call_user_func_array(array($this->handler, $method), $args);
|
||||
}
|
||||
}
|
||||
|
||||
namespace Symfony\Component\Debug\Exception;
|
||||
|
||||
use Symfony\Component\HttpKernel\Exception\FlattenException as LegacyFlattenException;
|
||||
use Symfony\Component\HttpKernel\Exception\HttpExceptionInterface;
|
||||
|
||||
/**
|
||||
@@ -20,7 +61,7 @@ use Symfony\Component\HttpKernel\Exception\HttpExceptionInterface;
|
||||
*
|
||||
* @author Fabien Potencier <fabien@symfony.com>
|
||||
*/
|
||||
class FlattenException
|
||||
class FlattenException extends LegacyFlattenException
|
||||
{
|
||||
private $message;
|
||||
private $code;
|
||||
@@ -222,7 +263,10 @@ class FlattenException
|
||||
if (++$count > 1e4) {
|
||||
return array('array', '*SKIPPED over 10000 entries*');
|
||||
}
|
||||
if (is_object($value)) {
|
||||
if ($value instanceof \__PHP_Incomplete_Class) {
|
||||
// is_object() returns false on PHP<=7.1
|
||||
$result[$key] = array('incomplete-object', $this->getClassNameFromIncomplete($value));
|
||||
} elseif (is_object($value)) {
|
||||
$result[$key] = array('object', get_class($value));
|
||||
} elseif (is_array($value)) {
|
||||
if ($level > 10) {
|
||||
@@ -236,9 +280,6 @@ class FlattenException
|
||||
$result[$key] = array('boolean', $value);
|
||||
} elseif (is_resource($value)) {
|
||||
$result[$key] = array('resource', get_resource_type($value));
|
||||
} elseif ($value instanceof \__PHP_Incomplete_Class) {
|
||||
// Special case of object, is_object will return false
|
||||
$result[$key] = array('incomplete-object', $this->getClassNameFromIncomplete($value));
|
||||
} else {
|
||||
$result[$key] = array('string', (string) $value);
|
||||
}
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
|
||||
namespace Symfony\Component\Debug;
|
||||
|
||||
use Symfony\Component\HttpFoundation\Response;
|
||||
use Symfony\Component\Debug\Exception\FlattenException;
|
||||
use Symfony\Component\Debug\Exception\OutOfMemoryException;
|
||||
|
||||
@@ -37,6 +38,14 @@ class ExceptionHandler
|
||||
|
||||
public function __construct($debug = true, $charset = null, $fileLinkFormat = null)
|
||||
{
|
||||
if (false !== strpos($charset, '%')) {
|
||||
@trigger_error('Providing $fileLinkFormat as second argument to '.__METHOD__.' is deprecated since version 2.8 and will be unsupported in 3.0. Please provide it as third argument, after $charset.', E_USER_DEPRECATED);
|
||||
|
||||
// Swap $charset and $fileLinkFormat for BC reasons
|
||||
$pivot = $fileLinkFormat;
|
||||
$fileLinkFormat = $charset;
|
||||
$charset = $pivot;
|
||||
}
|
||||
$this->debug = $debug;
|
||||
$this->charset = $charset ?: ini_get('default_charset') ?: 'UTF-8';
|
||||
$this->fileLinkFormat = $fileLinkFormat ?: ini_get('xdebug.file_link_format') ?: get_cfg_var('xdebug.file_link_format');
|
||||
@@ -49,7 +58,7 @@ class ExceptionHandler
|
||||
* @param string|null $charset The charset used by exception messages
|
||||
* @param string|null $fileLinkFormat The IDE link template
|
||||
*
|
||||
* @return ExceptionHandler The registered exception handler
|
||||
* @return static
|
||||
*/
|
||||
public static function register($debug = true, $charset = null, $fileLinkFormat = null)
|
||||
{
|
||||
@@ -71,8 +80,11 @@ class ExceptionHandler
|
||||
*
|
||||
* @return callable|null The previous exception handler if any
|
||||
*/
|
||||
public function setHandler(callable $handler = null)
|
||||
public function setHandler($handler)
|
||||
{
|
||||
if (null !== $handler && !is_callable($handler)) {
|
||||
throw new \LogicException('The exception handler must be a valid PHP callable.');
|
||||
}
|
||||
$old = $this->handler;
|
||||
$this->handler = $handler;
|
||||
|
||||
@@ -84,7 +96,7 @@ class ExceptionHandler
|
||||
*
|
||||
* @param string $format The format for links to source files
|
||||
*
|
||||
* @return string The previous file link format.
|
||||
* @return string The previous file link format
|
||||
*/
|
||||
public function setFileLinkFormat($format)
|
||||
{
|
||||
@@ -105,36 +117,20 @@ class ExceptionHandler
|
||||
public function handle(\Exception $exception)
|
||||
{
|
||||
if (null === $this->handler || $exception instanceof OutOfMemoryException) {
|
||||
$this->sendPhpResponse($exception);
|
||||
$this->failSafeHandle($exception);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
$caughtLength = $this->caughtLength = 0;
|
||||
|
||||
ob_start(function ($buffer) {
|
||||
$this->caughtBuffer = $buffer;
|
||||
|
||||
return '';
|
||||
});
|
||||
|
||||
$this->sendPhpResponse($exception);
|
||||
ob_start(array($this, 'catchOutput'));
|
||||
$this->failSafeHandle($exception);
|
||||
while (null === $this->caughtBuffer && ob_end_flush()) {
|
||||
// Empty loop, everything is in the condition
|
||||
}
|
||||
if (isset($this->caughtBuffer[0])) {
|
||||
ob_start(function ($buffer) {
|
||||
if ($this->caughtLength) {
|
||||
// use substr_replace() instead of substr() for mbstring overloading resistance
|
||||
$cleanBuffer = substr_replace($buffer, '', 0, $this->caughtLength);
|
||||
if (isset($cleanBuffer[0])) {
|
||||
$buffer = $cleanBuffer;
|
||||
}
|
||||
}
|
||||
|
||||
return $buffer;
|
||||
});
|
||||
|
||||
ob_start(array($this, 'cleanOutput'));
|
||||
echo $this->caughtBuffer;
|
||||
$caughtLength = ob_get_length();
|
||||
}
|
||||
@@ -151,6 +147,33 @@ class ExceptionHandler
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends a response for the given Exception.
|
||||
*
|
||||
* If you have the Symfony HttpFoundation component installed,
|
||||
* this method will use it to create and send the response. If not,
|
||||
* it will fallback to plain PHP functions.
|
||||
*
|
||||
* @param \Exception $exception An \Exception instance
|
||||
*/
|
||||
private function failSafeHandle(\Exception $exception)
|
||||
{
|
||||
if (class_exists('Symfony\Component\HttpFoundation\Response', false)
|
||||
&& __CLASS__ !== get_class($this)
|
||||
&& ($reflector = new \ReflectionMethod($this, 'createResponse'))
|
||||
&& __CLASS__ !== $reflector->class
|
||||
) {
|
||||
$response = $this->createResponse($exception);
|
||||
$response->sendHeaders();
|
||||
$response->sendContent();
|
||||
@trigger_error(sprintf("The %s::createResponse method is deprecated since 2.8 and won't be called anymore when handling an exception in 3.0.", $reflector->class), E_USER_DEPRECATED);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
$this->sendPhpResponse($exception);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends the error associated with the given Exception as a plain PHP response.
|
||||
*
|
||||
@@ -176,6 +199,26 @@ class ExceptionHandler
|
||||
echo $this->decorate($this->getContent($exception), $this->getStylesheet($exception));
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates the error Response associated with the given Exception.
|
||||
*
|
||||
* @param \Exception|FlattenException $exception An \Exception or FlattenException instance
|
||||
*
|
||||
* @return Response A Response instance
|
||||
*
|
||||
* @deprecated since 2.8, to be removed in 3.0.
|
||||
*/
|
||||
public function createResponse($exception)
|
||||
{
|
||||
@trigger_error('The '.__METHOD__.' method is deprecated since version 2.8 and will be removed in 3.0.', E_USER_DEPRECATED);
|
||||
|
||||
if (!$exception instanceof FlattenException) {
|
||||
$exception = FlattenException::create($exception);
|
||||
}
|
||||
|
||||
return Response::create($this->getHtml($exception), $exception->getStatusCode(), $exception->getHeaders())->setCharset($this->charset);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the full HTML content associated with the given exception.
|
||||
*
|
||||
@@ -218,7 +261,7 @@ class ExceptionHandler
|
||||
$ind = $count - $position + 1;
|
||||
$class = $this->formatClass($e['class']);
|
||||
$message = nl2br($this->escapeHtml($e['message']));
|
||||
$content .= sprintf(<<<EOF
|
||||
$content .= sprintf(<<<'EOF'
|
||||
<h2 class="block_exception clear_fix">
|
||||
<span class="exception_counter">%d/%d</span>
|
||||
<span class="exception_title">%s%s:</span>
|
||||
@@ -269,7 +312,7 @@ EOF;
|
||||
*/
|
||||
public function getStylesheet(FlattenException $exception)
|
||||
{
|
||||
return <<<EOF
|
||||
return <<<'EOF'
|
||||
.sf-reset { font: 11px Verdana, Arial, sans-serif; color: #333 }
|
||||
.sf-reset .clear { clear:both; height:0; font-size:0; line-height:0; }
|
||||
.sf-reset .clear_fix:after { display:block; height:0; clear:both; visibility:hidden; }
|
||||
@@ -299,6 +342,7 @@ EOF;
|
||||
border-bottom:1px solid #ccc;
|
||||
border-right:1px solid #ccc;
|
||||
border-left:1px solid #ccc;
|
||||
word-wrap: break-word;
|
||||
}
|
||||
.sf-reset .block_exception { background-color:#ddd; color: #333; padding:20px;
|
||||
-webkit-border-top-left-radius: 16px;
|
||||
@@ -404,11 +448,49 @@ EOF;
|
||||
return implode(', ', $result);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an UTF-8 and HTML encoded string.
|
||||
*
|
||||
* @deprecated since version 2.7, to be removed in 3.0.
|
||||
*/
|
||||
protected static function utf8Htmlize($str)
|
||||
{
|
||||
@trigger_error('The '.__METHOD__.' method is deprecated since version 2.7 and will be removed in 3.0.', E_USER_DEPRECATED);
|
||||
|
||||
return htmlspecialchars($str, ENT_QUOTES | (PHP_VERSION_ID >= 50400 ? ENT_SUBSTITUTE : 0), 'UTF-8');
|
||||
}
|
||||
|
||||
/**
|
||||
* HTML-encodes a string.
|
||||
*/
|
||||
private function escapeHtml($str)
|
||||
{
|
||||
return htmlspecialchars($str, ENT_QUOTES | ENT_SUBSTITUTE, $this->charset);
|
||||
return htmlspecialchars($str, ENT_QUOTES | (PHP_VERSION_ID >= 50400 ? ENT_SUBSTITUTE : 0), $this->charset);
|
||||
}
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
public function catchOutput($buffer)
|
||||
{
|
||||
$this->caughtBuffer = $buffer;
|
||||
|
||||
return '';
|
||||
}
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
public function cleanOutput($buffer)
|
||||
{
|
||||
if ($this->caughtLength) {
|
||||
// use substr_replace() instead of substr() for mbstring overloading resistance
|
||||
$cleanBuffer = substr_replace($buffer, '', 0, $this->caughtLength);
|
||||
if (isset($cleanBuffer[0])) {
|
||||
$buffer = $cleanBuffer;
|
||||
}
|
||||
}
|
||||
|
||||
return $buffer;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,6 +16,7 @@ use Symfony\Component\Debug\Exception\FatalErrorException;
|
||||
use Symfony\Component\Debug\DebugClassLoader;
|
||||
use Composer\Autoload\ClassLoader as ComposerClassLoader;
|
||||
use Symfony\Component\ClassLoader\ClassLoader as SymfonyClassLoader;
|
||||
use Symfony\Component\ClassLoader\UniversalClassLoader as SymfonyUniversalClassLoader;
|
||||
|
||||
/**
|
||||
* ErrorHandler for classes that do not exist.
|
||||
@@ -100,12 +101,17 @@ class ClassNotFoundFatalErrorHandler implements FatalErrorHandlerInterface
|
||||
if ($function[0] instanceof DebugClassLoader) {
|
||||
$function = $function[0]->getClassLoader();
|
||||
|
||||
// @deprecated since version 2.5. Returning an object from DebugClassLoader::getClassLoader() is deprecated.
|
||||
if (is_object($function)) {
|
||||
$function = array($function);
|
||||
}
|
||||
|
||||
if (!is_array($function)) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if ($function[0] instanceof ComposerClassLoader || $function[0] instanceof SymfonyClassLoader) {
|
||||
if ($function[0] instanceof ComposerClassLoader || $function[0] instanceof SymfonyClassLoader || $function[0] instanceof SymfonyUniversalClassLoader) {
|
||||
foreach ($function[0]->getPrefixes() as $prefix => $paths) {
|
||||
foreach ($paths as $path) {
|
||||
$classes = array_merge($classes, $this->findClassInPath($path, $class, $prefix));
|
||||
@@ -173,7 +179,7 @@ class ClassNotFoundFatalErrorHandler implements FatalErrorHandlerInterface
|
||||
);
|
||||
|
||||
if ($prefix) {
|
||||
$candidates = array_filter($candidates, function ($candidate) use ($prefix) {return 0 === strpos($candidate, $prefix);});
|
||||
$candidates = array_filter($candidates, function ($candidate) use ($prefix) { return 0 === strpos($candidate, $prefix); });
|
||||
}
|
||||
|
||||
// We cannot use the autoloader here as most of them use require; but if the class
|
||||
@@ -201,6 +207,6 @@ class ClassNotFoundFatalErrorHandler implements FatalErrorHandlerInterface
|
||||
*/
|
||||
private function classExists($class)
|
||||
{
|
||||
return class_exists($class, false) || interface_exists($class, false) || trait_exists($class, false);
|
||||
return class_exists($class, false) || interface_exists($class, false) || (function_exists('trait_exists') && trait_exists($class, false));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -36,8 +36,13 @@ class UndefinedMethodFatalErrorHandler implements FatalErrorHandlerInterface
|
||||
|
||||
$message = sprintf('Attempted to call an undefined method named "%s" of class "%s".', $methodName, $className);
|
||||
|
||||
if (!class_exists($className) || null === $methods = get_class_methods($className)) {
|
||||
// failed to get the class or its methods on which an unknown method was called (for example on an anonymous class)
|
||||
return new UndefinedMethodException($message, $exception);
|
||||
}
|
||||
|
||||
$candidates = array();
|
||||
foreach (get_class_methods($className) as $definedMethodName) {
|
||||
foreach ($methods as $definedMethodName) {
|
||||
$lev = levenshtein($methodName, $definedMethodName);
|
||||
if ($lev <= strlen($methodName) / 3 || false !== strpos($definedMethodName, $methodName)) {
|
||||
$candidates[] = $definedMethodName;
|
||||
@@ -52,6 +57,7 @@ class UndefinedMethodFatalErrorHandler implements FatalErrorHandlerInterface
|
||||
} else {
|
||||
$candidates = '"'.$last;
|
||||
}
|
||||
|
||||
$message .= "\nDid you mean to call ".$candidates;
|
||||
}
|
||||
|
||||
|
||||
2
LICENSE
2
LICENSE
@@ -1,4 +1,4 @@
|
||||
Copyright (c) 2004-2015 Fabien Potencier
|
||||
Copyright (c) 2004-2017 Fabien Potencier
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
|
||||
41
README.md
41
README.md
@@ -1,42 +1,13 @@
|
||||
Debug Component
|
||||
===============
|
||||
|
||||
Debug provides tools to make debugging easier.
|
||||
|
||||
Enabling all debug tools is as easy as calling the `enable()` method on the
|
||||
main `Debug` class:
|
||||
|
||||
```php
|
||||
use Symfony\Component\Debug\Debug;
|
||||
|
||||
Debug::enable();
|
||||
```
|
||||
|
||||
You can also use the tools individually:
|
||||
|
||||
```php
|
||||
use Symfony\Component\Debug\DebugClassLoader;
|
||||
use Symfony\Component\Debug\ErrorHandler;
|
||||
use Symfony\Component\Debug\ExceptionHandler;
|
||||
|
||||
if ('cli' !== php_sapi_name()) {
|
||||
ini_set('display_errors', 0);
|
||||
ExceptionHandler::register();
|
||||
} elseif (!ini_get('log_errors') || ini_get('error_log')) {
|
||||
ini_set('display_errors', 1);
|
||||
}
|
||||
ErrorHandler::register();
|
||||
DebugClassLoader::enable();
|
||||
```
|
||||
|
||||
This component can optionally take advantage of the features of the HttpKernel
|
||||
component.
|
||||
The Debug component provides tools to ease debugging PHP code.
|
||||
|
||||
Resources
|
||||
---------
|
||||
|
||||
You can run the unit tests with the following command:
|
||||
|
||||
$ cd path/to/Symfony/Component/Debug/
|
||||
$ composer install
|
||||
$ phpunit
|
||||
* [Documentation](https://symfony.com/doc/current/components/debug/index.html)
|
||||
* [Contributing](https://symfony.com/doc/current/contributing/index.html)
|
||||
* [Report issues](https://github.com/symfony/symfony/issues) and
|
||||
[send Pull Requests](https://github.com/symfony/symfony/pulls)
|
||||
in the [main Symfony repository](https://github.com/symfony/symfony)
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
Symfony Debug Extension
|
||||
=======================
|
||||
Symfony Debug Extension for PHP 5
|
||||
=================================
|
||||
|
||||
This extension publishes several functions to help building powerful debugging tools.
|
||||
It is compatible with PHP 5.3, 5.4, 5.5 and 5.6; with ZTS and non-ZTS modes.
|
||||
It is not required thus not provided for PHP 7.
|
||||
|
||||
symfony_zval_info()
|
||||
-------------------
|
||||
@@ -122,7 +124,6 @@ array(3) {
|
||||
Usage
|
||||
-----
|
||||
|
||||
The extension is compatible with ZTS mode, and should be supported by PHP5.3, 5.4, 5.5 and 5.6.
|
||||
To enable the extension from source, run:
|
||||
|
||||
```
|
||||
|
||||
@@ -1,14 +1,14 @@
|
||||
--TEST--
|
||||
Test symfony_zval_info API
|
||||
--SKIPIF--
|
||||
<?php if (!extension_loaded("symfony_debug")) print "skip"; ?>
|
||||
<?php if (!extension_loaded('symfony_debug')) print 'skip'; ?>
|
||||
--FILE--
|
||||
<?php
|
||||
|
||||
$int = 42;
|
||||
$float = 42.42;
|
||||
$str = "foobar";
|
||||
$object = new StdClass;
|
||||
$str = 'foobar';
|
||||
$object = new StdClass();
|
||||
$array = array('foo', 'bar');
|
||||
$resource = tmpfile();
|
||||
$null = null;
|
||||
@@ -17,15 +17,17 @@ $bool = true;
|
||||
$anotherint = 42;
|
||||
$refcount2 = &$anotherint;
|
||||
|
||||
$var = array('int' => $int,
|
||||
'float' => $float,
|
||||
'str' => $str,
|
||||
'object' => $object,
|
||||
'array' => $array,
|
||||
'resource' => $resource,
|
||||
'null' => $null,
|
||||
'bool' => $bool,
|
||||
'refcount' => &$refcount2);
|
||||
$var = array(
|
||||
'int' => $int,
|
||||
'float' => $float,
|
||||
'str' => $str,
|
||||
'object' => $object,
|
||||
'array' => $array,
|
||||
'resource' => $resource,
|
||||
'null' => $null,
|
||||
'bool' => $bool,
|
||||
'refcount' => &$refcount2,
|
||||
);
|
||||
|
||||
var_dump(symfony_zval_info('int', $var));
|
||||
var_dump(symfony_zval_info('float', $var));
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
--TEST--
|
||||
Test symfony_debug_backtrace in case of fatal error
|
||||
--SKIPIF--
|
||||
<?php if (!extension_loaded("symfony_debug")) print "skip"; ?>
|
||||
<?php if (!extension_loaded('symfony_debug')) print 'skip'; ?>
|
||||
--FILE--
|
||||
<?php
|
||||
|
||||
@@ -18,7 +18,6 @@ function foo()
|
||||
function bt()
|
||||
{
|
||||
print_r(symfony_debug_backtrace());
|
||||
|
||||
}
|
||||
|
||||
register_shutdown_function('bt');
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
--TEST--
|
||||
Test symfony_debug_backtrace in case of non fatal error
|
||||
--SKIPIF--
|
||||
<?php if (!extension_loaded("symfony_debug")) print "skip"; ?>
|
||||
<?php if (!extension_loaded('symfony_debug')) print 'skip'; ?>
|
||||
--FILE--
|
||||
<?php
|
||||
|
||||
@@ -13,7 +13,6 @@ function bar()
|
||||
function bt()
|
||||
{
|
||||
print_r(symfony_debug_backtrace());
|
||||
|
||||
}
|
||||
|
||||
bar();
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
--TEST--
|
||||
Test ErrorHandler in case of fatal error
|
||||
--SKIPIF--
|
||||
<?php if (!extension_loaded("symfony_debug")) print "skip"; ?>
|
||||
<?php if (!extension_loaded('symfony_debug')) print 'skip'; ?>
|
||||
--FILE--
|
||||
<?php
|
||||
|
||||
|
||||
@@ -11,14 +11,14 @@
|
||||
|
||||
namespace Symfony\Component\Debug\Tests;
|
||||
|
||||
use PHPUnit\Framework\TestCase;
|
||||
use Symfony\Component\Debug\DebugClassLoader;
|
||||
use Symfony\Component\Debug\ErrorHandler;
|
||||
use Symfony\Component\Debug\Exception\ContextErrorException;
|
||||
|
||||
class DebugClassLoaderTest extends \PHPUnit_Framework_TestCase
|
||||
class DebugClassLoaderTest extends TestCase
|
||||
{
|
||||
/**
|
||||
* @var int Error reporting level before running tests.
|
||||
* @var int Error reporting level before running tests
|
||||
*/
|
||||
private $errorReporting;
|
||||
|
||||
@@ -26,7 +26,7 @@ class DebugClassLoaderTest extends \PHPUnit_Framework_TestCase
|
||||
|
||||
protected function setUp()
|
||||
{
|
||||
$this->errorReporting = error_reporting(E_ALL);
|
||||
$this->errorReporting = error_reporting(E_ALL | E_STRICT);
|
||||
$this->loader = new ClassLoader();
|
||||
spl_autoload_register(array($this->loader, 'loadClass'), true, true);
|
||||
DebugClassLoader::enable();
|
||||
@@ -108,6 +108,8 @@ class DebugClassLoaderTest extends \PHPUnit_Framework_TestCase
|
||||
$this->fail('ContextErrorException expected');
|
||||
} catch (\ErrorException $exception) {
|
||||
// if an exception is thrown, the test passed
|
||||
restore_error_handler();
|
||||
restore_exception_handler();
|
||||
$this->assertStringStartsWith(__FILE__, $exception->getFile());
|
||||
if (PHP_VERSION_ID < 70000) {
|
||||
$this->assertRegExp('/^Runtime Notice: Declaration/', $exception->getMessage());
|
||||
@@ -116,9 +118,11 @@ class DebugClassLoaderTest extends \PHPUnit_Framework_TestCase
|
||||
$this->assertRegExp('/^Warning: Declaration/', $exception->getMessage());
|
||||
$this->assertEquals(E_WARNING, $exception->getSeverity());
|
||||
}
|
||||
} finally {
|
||||
} catch (\Exception $exception) {
|
||||
restore_error_handler();
|
||||
restore_exception_handler();
|
||||
|
||||
throw $exception;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -171,7 +175,7 @@ class DebugClassLoaderTest extends \PHPUnit_Framework_TestCase
|
||||
*/
|
||||
public function testDeprecatedSuper($class, $super, $type)
|
||||
{
|
||||
set_error_handler('var_dump', 0);
|
||||
set_error_handler(function () { return false; });
|
||||
$e = error_reporting(0);
|
||||
trigger_error('', E_USER_DEPRECATED);
|
||||
|
||||
@@ -199,9 +203,31 @@ class DebugClassLoaderTest extends \PHPUnit_Framework_TestCase
|
||||
);
|
||||
}
|
||||
|
||||
public function testInterfaceExtendsDeprecatedInterface()
|
||||
{
|
||||
set_error_handler(function () { return false; });
|
||||
$e = error_reporting(0);
|
||||
trigger_error('', E_USER_NOTICE);
|
||||
|
||||
class_exists('Test\\'.__NAMESPACE__.'\\NonDeprecatedInterfaceClass', true);
|
||||
|
||||
error_reporting($e);
|
||||
restore_error_handler();
|
||||
|
||||
$lastError = error_get_last();
|
||||
unset($lastError['file'], $lastError['line']);
|
||||
|
||||
$xError = array(
|
||||
'type' => E_USER_NOTICE,
|
||||
'message' => '',
|
||||
);
|
||||
|
||||
$this->assertSame($xError, $lastError);
|
||||
}
|
||||
|
||||
public function testDeprecatedSuperInSameNamespace()
|
||||
{
|
||||
set_error_handler('var_dump', 0);
|
||||
set_error_handler(function () { return false; });
|
||||
$e = error_reporting(0);
|
||||
trigger_error('', E_USER_NOTICE);
|
||||
|
||||
@@ -227,7 +253,7 @@ class DebugClassLoaderTest extends \PHPUnit_Framework_TestCase
|
||||
$this->markTestSkipped('PHP7 already prevents using reserved names.');
|
||||
}
|
||||
|
||||
set_error_handler('var_dump', 0);
|
||||
set_error_handler(function () { return false; });
|
||||
$e = error_reporting(0);
|
||||
trigger_error('', E_USER_NOTICE);
|
||||
|
||||
@@ -285,6 +311,8 @@ class ClassLoader
|
||||
eval('namespace Test\\'.__NAMESPACE__.'; class DeprecatedParentClass extends \\'.__NAMESPACE__.'\Fixtures\DeprecatedClass {}');
|
||||
} elseif ('Test\\'.__NAMESPACE__.'\DeprecatedInterfaceClass' === $class) {
|
||||
eval('namespace Test\\'.__NAMESPACE__.'; class DeprecatedInterfaceClass implements \\'.__NAMESPACE__.'\Fixtures\DeprecatedInterface {}');
|
||||
} elseif ('Test\\'.__NAMESPACE__.'\NonDeprecatedInterfaceClass' === $class) {
|
||||
eval('namespace Test\\'.__NAMESPACE__.'; class NonDeprecatedInterfaceClass implements \\'.__NAMESPACE__.'\Fixtures\NonDeprecatedInterface {}');
|
||||
} elseif ('Test\\'.__NAMESPACE__.'\Float' === $class) {
|
||||
eval('namespace Test\\'.__NAMESPACE__.'; class Float {}');
|
||||
}
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
|
||||
namespace Symfony\Component\Debug\Tests;
|
||||
|
||||
use PHPUnit\Framework\TestCase;
|
||||
use Psr\Log\LogLevel;
|
||||
use Symfony\Component\Debug\ErrorHandler;
|
||||
use Symfony\Component\Debug\BufferingLogger;
|
||||
@@ -22,7 +23,7 @@ use Symfony\Component\Debug\Exception\ContextErrorException;
|
||||
* @author Robert Schönthal <seroscho@googlemail.com>
|
||||
* @author Nicolas Grekas <p@tchwork.com>
|
||||
*/
|
||||
class ErrorHandlerTest extends \PHPUnit_Framework_TestCase
|
||||
class ErrorHandlerTest extends TestCase
|
||||
{
|
||||
public function testRegister()
|
||||
{
|
||||
@@ -73,6 +74,9 @@ class ErrorHandlerTest extends \PHPUnit_Framework_TestCase
|
||||
$this->fail('ContextErrorException expected');
|
||||
} catch (ContextErrorException $exception) {
|
||||
// if an exception is thrown, the test passed
|
||||
restore_error_handler();
|
||||
restore_exception_handler();
|
||||
|
||||
$this->assertEquals(E_NOTICE, $exception->getSeverity());
|
||||
$this->assertEquals(__FILE__, $exception->getFile());
|
||||
$this->assertRegExp('/^Notice: Undefined variable: (foo|bar)/', $exception->getMessage());
|
||||
@@ -93,9 +97,11 @@ class ErrorHandlerTest extends \PHPUnit_Framework_TestCase
|
||||
$this->assertEquals(__CLASS__, $trace[2]['class']);
|
||||
$this->assertEquals(__FUNCTION__, $trace[2]['function']);
|
||||
$this->assertEquals('->', $trace[2]['type']);
|
||||
} finally {
|
||||
} catch (\Exception $e) {
|
||||
restore_error_handler();
|
||||
restore_exception_handler();
|
||||
|
||||
throw $e;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -113,9 +119,14 @@ class ErrorHandlerTest extends \PHPUnit_Framework_TestCase
|
||||
$handler = ErrorHandler::register();
|
||||
$handler->throwAt(3, true);
|
||||
$this->assertEquals(3 | E_RECOVERABLE_ERROR | E_USER_ERROR, $handler->throwAt(0));
|
||||
} finally {
|
||||
|
||||
restore_error_handler();
|
||||
restore_exception_handler();
|
||||
} catch (\Exception $e) {
|
||||
restore_error_handler();
|
||||
restore_exception_handler();
|
||||
|
||||
throw $e;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -124,7 +135,7 @@ class ErrorHandlerTest extends \PHPUnit_Framework_TestCase
|
||||
try {
|
||||
$handler = ErrorHandler::register();
|
||||
|
||||
$logger = $this->getMock('Psr\Log\LoggerInterface');
|
||||
$logger = $this->getMockBuilder('Psr\Log\LoggerInterface')->getMock();
|
||||
|
||||
$handler->setDefaultLogger($logger, E_NOTICE);
|
||||
$handler->setDefaultLogger($logger, array(E_USER_NOTICE => LogLevel::CRITICAL));
|
||||
@@ -147,9 +158,14 @@ class ErrorHandlerTest extends \PHPUnit_Framework_TestCase
|
||||
E_CORE_ERROR => array(null, LogLevel::CRITICAL),
|
||||
);
|
||||
$this->assertSame($loggers, $handler->setLoggers(array()));
|
||||
} finally {
|
||||
|
||||
restore_error_handler();
|
||||
restore_exception_handler();
|
||||
} catch (\Exception $e) {
|
||||
restore_error_handler();
|
||||
restore_exception_handler();
|
||||
|
||||
throw $e;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -198,15 +214,16 @@ class ErrorHandlerTest extends \PHPUnit_Framework_TestCase
|
||||
restore_error_handler();
|
||||
restore_exception_handler();
|
||||
|
||||
$logger = $this->getMock('Psr\Log\LoggerInterface');
|
||||
$logger = $this->getMockBuilder('Psr\Log\LoggerInterface')->getMock();
|
||||
|
||||
$warnArgCheck = function ($logLevel, $message, $context) {
|
||||
$this->assertEquals('info', $logLevel);
|
||||
$this->assertEquals('foo', $message);
|
||||
$this->assertArrayHasKey('type', $context);
|
||||
$this->assertEquals($context['type'], E_USER_DEPRECATED);
|
||||
$this->assertArrayHasKey('stack', $context);
|
||||
$this->assertInternalType('array', $context['stack']);
|
||||
$that = $this;
|
||||
$warnArgCheck = function ($logLevel, $message, $context) use ($that) {
|
||||
$that->assertEquals('info', $logLevel);
|
||||
$that->assertEquals('foo', $message);
|
||||
$that->assertArrayHasKey('type', $context);
|
||||
$that->assertEquals($context['type'], E_USER_DEPRECATED);
|
||||
$that->assertArrayHasKey('stack', $context);
|
||||
$that->assertInternalType('array', $context['stack']);
|
||||
};
|
||||
|
||||
$logger
|
||||
@@ -222,12 +239,13 @@ class ErrorHandlerTest extends \PHPUnit_Framework_TestCase
|
||||
restore_error_handler();
|
||||
restore_exception_handler();
|
||||
|
||||
$logger = $this->getMock('Psr\Log\LoggerInterface');
|
||||
$logger = $this->getMockBuilder('Psr\Log\LoggerInterface')->getMock();
|
||||
|
||||
$logArgCheck = function ($level, $message, $context) {
|
||||
$this->assertEquals('Undefined variable: undefVar', $message);
|
||||
$this->assertArrayHasKey('type', $context);
|
||||
$this->assertEquals($context['type'], E_NOTICE);
|
||||
$that = $this;
|
||||
$logArgCheck = function ($level, $message, $context) use ($that) {
|
||||
$that->assertEquals('Undefined variable: undefVar', $message);
|
||||
$that->assertArrayHasKey('type', $context);
|
||||
$that->assertEquals($context['type'], E_NOTICE);
|
||||
};
|
||||
|
||||
$logger
|
||||
@@ -268,22 +286,28 @@ class ErrorHandlerTest extends \PHPUnit_Framework_TestCase
|
||||
}
|
||||
|
||||
$this->assertSame($x, $e);
|
||||
} finally {
|
||||
|
||||
restore_error_handler();
|
||||
restore_exception_handler();
|
||||
} catch (\Exception $e) {
|
||||
restore_error_handler();
|
||||
restore_exception_handler();
|
||||
|
||||
throw $e;
|
||||
}
|
||||
}
|
||||
|
||||
public function testHandleDeprecation()
|
||||
{
|
||||
$logArgCheck = function ($level, $message, $context) {
|
||||
$this->assertEquals(LogLevel::INFO, $level);
|
||||
$this->assertArrayHasKey('level', $context);
|
||||
$this->assertEquals(E_RECOVERABLE_ERROR | E_USER_ERROR | E_DEPRECATED | E_USER_DEPRECATED, $context['level']);
|
||||
$this->assertArrayHasKey('stack', $context);
|
||||
$that = $this;
|
||||
$logArgCheck = function ($level, $message, $context) use ($that) {
|
||||
$that->assertEquals(LogLevel::INFO, $level);
|
||||
$that->assertArrayHasKey('level', $context);
|
||||
$that->assertEquals(E_RECOVERABLE_ERROR | E_USER_ERROR | E_DEPRECATED | E_USER_DEPRECATED, $context['level']);
|
||||
$that->assertArrayHasKey('stack', $context);
|
||||
};
|
||||
|
||||
$logger = $this->getMock('Psr\Log\LoggerInterface');
|
||||
$logger = $this->getMockBuilder('Psr\Log\LoggerInterface')->getMock();
|
||||
$logger
|
||||
->expects($this->once())
|
||||
->method('log')
|
||||
@@ -302,12 +326,13 @@ class ErrorHandlerTest extends \PHPUnit_Framework_TestCase
|
||||
|
||||
$exception = new \Exception('foo');
|
||||
|
||||
$logger = $this->getMock('Psr\Log\LoggerInterface');
|
||||
$logger = $this->getMockBuilder('Psr\Log\LoggerInterface')->getMock();
|
||||
|
||||
$logArgCheck = function ($level, $message, $context) {
|
||||
$this->assertEquals('Uncaught Exception: foo', $message);
|
||||
$this->assertArrayHasKey('type', $context);
|
||||
$this->assertEquals($context['type'], E_ERROR);
|
||||
$that = $this;
|
||||
$logArgCheck = function ($level, $message, $context) use ($that) {
|
||||
$that->assertEquals('Uncaught Exception: foo', $message);
|
||||
$that->assertArrayHasKey('type', $context);
|
||||
$that->assertEquals($context['type'], E_ERROR);
|
||||
};
|
||||
|
||||
$logger
|
||||
@@ -325,14 +350,20 @@ class ErrorHandlerTest extends \PHPUnit_Framework_TestCase
|
||||
$this->assertSame($exception, $e);
|
||||
}
|
||||
|
||||
$handler->setExceptionHandler(function ($e) use ($exception) {
|
||||
$this->assertSame($exception, $e);
|
||||
$that = $this;
|
||||
$handler->setExceptionHandler(function ($e) use ($exception, $that) {
|
||||
$that->assertSame($exception, $e);
|
||||
});
|
||||
|
||||
$handler->handleException($exception);
|
||||
} finally {
|
||||
|
||||
restore_error_handler();
|
||||
restore_exception_handler();
|
||||
} catch (\Exception $e) {
|
||||
restore_error_handler();
|
||||
restore_exception_handler();
|
||||
|
||||
throw $e;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -342,7 +373,7 @@ class ErrorHandlerTest extends \PHPUnit_Framework_TestCase
|
||||
$handler = ErrorHandler::register();
|
||||
$handler->screamAt(E_USER_WARNING);
|
||||
|
||||
$logger = $this->getMock('Psr\Log\LoggerInterface');
|
||||
$logger = $this->getMockBuilder('Psr\Log\LoggerInterface')->getMock();
|
||||
|
||||
$logger
|
||||
->expects($this->exactly(2))
|
||||
@@ -359,9 +390,14 @@ class ErrorHandlerTest extends \PHPUnit_Framework_TestCase
|
||||
@trigger_error('Silenced warning', E_USER_WARNING);
|
||||
$logger->log(LogLevel::WARNING, 'Dummy log');
|
||||
ErrorHandler::unstackErrors();
|
||||
} finally {
|
||||
|
||||
restore_error_handler();
|
||||
restore_exception_handler();
|
||||
} catch (\Exception $e) {
|
||||
restore_error_handler();
|
||||
restore_exception_handler();
|
||||
|
||||
throw $e;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -400,7 +436,7 @@ class ErrorHandlerTest extends \PHPUnit_Framework_TestCase
|
||||
|
||||
$bootLogger->log($expectedLog[0], $expectedLog[1], $expectedLog[2]);
|
||||
|
||||
$mockLogger = $this->getMock('Psr\Log\LoggerInterface');
|
||||
$mockLogger = $this->getMockBuilder('Psr\Log\LoggerInterface')->getMock();
|
||||
$mockLogger->expects($this->once())
|
||||
->method('log')
|
||||
->with(LogLevel::WARNING, 'Foo message', $expectedLog[2]);
|
||||
@@ -420,12 +456,13 @@ class ErrorHandlerTest extends \PHPUnit_Framework_TestCase
|
||||
'line' => 123,
|
||||
);
|
||||
|
||||
$logger = $this->getMock('Psr\Log\LoggerInterface');
|
||||
$logger = $this->getMockBuilder('Psr\Log\LoggerInterface')->getMock();
|
||||
|
||||
$logArgCheck = function ($level, $message, $context) {
|
||||
$this->assertEquals('Fatal Parse Error: foo', $message);
|
||||
$this->assertArrayHasKey('type', $context);
|
||||
$this->assertEquals($context['type'], E_PARSE);
|
||||
$that = $this;
|
||||
$logArgCheck = function ($level, $message, $context) use ($that) {
|
||||
$that->assertEquals('Fatal Parse Error: foo', $message);
|
||||
$that->assertArrayHasKey('type', $context);
|
||||
$that->assertEquals($context['type'], E_PARSE);
|
||||
};
|
||||
|
||||
$logger
|
||||
@@ -448,12 +485,30 @@ class ErrorHandlerTest extends \PHPUnit_Framework_TestCase
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @requires PHP 7
|
||||
*/
|
||||
public function testHandleErrorException()
|
||||
{
|
||||
$exception = new \Error("Class 'Foo' not found");
|
||||
|
||||
$handler = new ErrorHandler();
|
||||
$handler->setExceptionHandler(function () use (&$args) {
|
||||
$args = func_get_args();
|
||||
});
|
||||
|
||||
$handler->handleException($exception);
|
||||
|
||||
$this->assertInstanceOf('Symfony\Component\Debug\Exception\ClassNotFoundException', $args[0]);
|
||||
$this->assertStringStartsWith("Attempted to load class \"Foo\" from the global namespace.\nDid you forget a \"use\" statement", $args[0]->getMessage());
|
||||
}
|
||||
|
||||
public function testHandleFatalErrorOnHHVM()
|
||||
{
|
||||
try {
|
||||
$handler = ErrorHandler::register();
|
||||
|
||||
$logger = $this->getMock('Psr\Log\LoggerInterface');
|
||||
$logger = $this->getMockBuilder('Psr\Log\LoggerInterface')->getMock();
|
||||
$logger
|
||||
->expects($this->once())
|
||||
->method('log')
|
||||
@@ -483,9 +538,56 @@ class ErrorHandlerTest extends \PHPUnit_Framework_TestCase
|
||||
|
||||
call_user_func_array(array($handler, 'handleError'), $error);
|
||||
$handler->handleFatalError($error);
|
||||
} finally {
|
||||
|
||||
restore_error_handler();
|
||||
restore_exception_handler();
|
||||
} catch (\Exception $e) {
|
||||
restore_error_handler();
|
||||
restore_exception_handler();
|
||||
|
||||
throw $e;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @group legacy
|
||||
*/
|
||||
public function testLegacyInterface()
|
||||
{
|
||||
try {
|
||||
$handler = ErrorHandler::register(0);
|
||||
$this->assertFalse($handler->handle(0, 'foo', 'foo.php', 12, array()));
|
||||
|
||||
restore_error_handler();
|
||||
restore_exception_handler();
|
||||
|
||||
$logger = $this->getMockBuilder('Psr\Log\LoggerInterface')->getMock();
|
||||
|
||||
$that = $this;
|
||||
$logArgCheck = function ($level, $message, $context) use ($that) {
|
||||
$that->assertEquals('Undefined variable: undefVar', $message);
|
||||
$that->assertArrayHasKey('type', $context);
|
||||
$that->assertEquals($context['type'], E_NOTICE);
|
||||
};
|
||||
|
||||
$logger
|
||||
->expects($this->once())
|
||||
->method('log')
|
||||
->will($this->returnCallback($logArgCheck))
|
||||
;
|
||||
|
||||
$handler = ErrorHandler::register(E_NOTICE);
|
||||
@$handler->setLogger($logger, 'scream');
|
||||
unset($undefVar);
|
||||
@$undefVar++;
|
||||
|
||||
restore_error_handler();
|
||||
restore_exception_handler();
|
||||
} catch (\Exception $e) {
|
||||
restore_error_handler();
|
||||
restore_exception_handler();
|
||||
|
||||
throw $e;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
|
||||
namespace Symfony\Component\Debug\Tests\Exception;
|
||||
|
||||
use PHPUnit\Framework\TestCase;
|
||||
use Symfony\Component\Debug\Exception\FlattenException;
|
||||
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
|
||||
use Symfony\Component\HttpKernel\Exception\MethodNotAllowedHttpException;
|
||||
@@ -27,7 +28,7 @@ use Symfony\Component\HttpKernel\Exception\ServiceUnavailableHttpException;
|
||||
use Symfony\Component\HttpKernel\Exception\TooManyRequestsHttpException;
|
||||
use Symfony\Component\HttpKernel\Exception\UnsupportedMediaTypeHttpException;
|
||||
|
||||
class FlattenExceptionTest extends \PHPUnit_Framework_TestCase
|
||||
class FlattenExceptionTest extends TestCase
|
||||
{
|
||||
public function testStatusCode()
|
||||
{
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
|
||||
namespace Symfony\Component\Debug\Tests;
|
||||
|
||||
use PHPUnit\Framework\TestCase;
|
||||
use Symfony\Component\Debug\ExceptionHandler;
|
||||
use Symfony\Component\Debug\Exception\OutOfMemoryException;
|
||||
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
|
||||
@@ -18,7 +19,7 @@ use Symfony\Component\HttpKernel\Exception\MethodNotAllowedHttpException;
|
||||
|
||||
require_once __DIR__.'/HeaderMock.php';
|
||||
|
||||
class ExceptionHandlerTest extends \PHPUnit_Framework_TestCase
|
||||
class ExceptionHandlerTest extends TestCase
|
||||
{
|
||||
protected function setUp()
|
||||
{
|
||||
@@ -100,15 +101,16 @@ class ExceptionHandlerTest extends \PHPUnit_Framework_TestCase
|
||||
{
|
||||
$exception = new \Exception('foo');
|
||||
|
||||
$handler = $this->getMock('Symfony\Component\Debug\ExceptionHandler', array('sendPhpResponse'));
|
||||
$handler = $this->getMockBuilder('Symfony\Component\Debug\ExceptionHandler')->setMethods(array('sendPhpResponse'))->getMock();
|
||||
$handler
|
||||
->expects($this->exactly(2))
|
||||
->method('sendPhpResponse');
|
||||
|
||||
$handler->handle($exception);
|
||||
|
||||
$handler->setHandler(function ($e) use ($exception) {
|
||||
$this->assertSame($exception, $e);
|
||||
$that = $this;
|
||||
$handler->setHandler(function ($e) use ($exception, $that) {
|
||||
$that->assertSame($exception, $e);
|
||||
});
|
||||
|
||||
$handler->handle($exception);
|
||||
@@ -118,13 +120,14 @@ class ExceptionHandlerTest extends \PHPUnit_Framework_TestCase
|
||||
{
|
||||
$exception = new OutOfMemoryException('foo', 0, E_ERROR, __FILE__, __LINE__);
|
||||
|
||||
$handler = $this->getMock('Symfony\Component\Debug\ExceptionHandler', array('sendPhpResponse'));
|
||||
$handler = $this->getMockBuilder('Symfony\Component\Debug\ExceptionHandler')->setMethods(array('sendPhpResponse'))->getMock();
|
||||
$handler
|
||||
->expects($this->once())
|
||||
->method('sendPhpResponse');
|
||||
|
||||
$handler->setHandler(function ($e) {
|
||||
$this->fail('OutOfMemoryException should bypass the handler');
|
||||
$that = $this;
|
||||
$handler->setHandler(function ($e) use ($that) {
|
||||
$that->fail('OutOfMemoryException should bypass the handler');
|
||||
});
|
||||
|
||||
$handler->handle($exception);
|
||||
|
||||
@@ -11,13 +11,15 @@
|
||||
|
||||
namespace Symfony\Component\Debug\Tests\FatalErrorHandler;
|
||||
|
||||
use Symfony\Component\Debug\Exception\FatalErrorException;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
use Symfony\Component\ClassLoader\ClassLoader as SymfonyClassLoader;
|
||||
use Symfony\Component\ClassLoader\UniversalClassLoader as SymfonyUniversalClassLoader;
|
||||
use Symfony\Component\Debug\Exception\FatalErrorException;
|
||||
use Symfony\Component\Debug\FatalErrorHandler\ClassNotFoundFatalErrorHandler;
|
||||
use Symfony\Component\Debug\DebugClassLoader;
|
||||
use Composer\Autoload\ClassLoader as ComposerClassLoader;
|
||||
|
||||
class ClassNotFoundFatalErrorHandlerTest extends \PHPUnit_Framework_TestCase
|
||||
class ClassNotFoundFatalErrorHandlerTest extends TestCase
|
||||
{
|
||||
public static function setUpBeforeClass()
|
||||
{
|
||||
@@ -67,6 +69,27 @@ class ClassNotFoundFatalErrorHandlerTest extends \PHPUnit_Framework_TestCase
|
||||
$this->assertSame($error['line'], $exception->getLine());
|
||||
}
|
||||
|
||||
/**
|
||||
* @group legacy
|
||||
*/
|
||||
public function testLegacyHandleClassNotFound()
|
||||
{
|
||||
$prefixes = array('Symfony\Component\Debug\Exception\\' => realpath(__DIR__.'/../../Exception'));
|
||||
$symfonyUniversalClassLoader = new SymfonyUniversalClassLoader();
|
||||
$symfonyUniversalClassLoader->registerPrefixes($prefixes);
|
||||
|
||||
$this->testHandleClassNotFound(
|
||||
array(
|
||||
'type' => 1,
|
||||
'line' => 12,
|
||||
'file' => 'foo.php',
|
||||
'message' => 'Class \'Foo\\Bar\\UndefinedFunctionException\' not found',
|
||||
),
|
||||
"Attempted to load class \"UndefinedFunctionException\" from namespace \"Foo\Bar\".\nDid you forget a \"use\" statement for \"Symfony\Component\Debug\Exception\UndefinedFunctionException\"?",
|
||||
array($symfonyUniversalClassLoader, 'loadClass')
|
||||
);
|
||||
}
|
||||
|
||||
public function provideClassNotFoundData()
|
||||
{
|
||||
$prefixes = array('Symfony\Component\Debug\Exception\\' => realpath(__DIR__.'/../../Exception'));
|
||||
|
||||
@@ -11,10 +11,11 @@
|
||||
|
||||
namespace Symfony\Component\Debug\Tests\FatalErrorHandler;
|
||||
|
||||
use PHPUnit\Framework\TestCase;
|
||||
use Symfony\Component\Debug\Exception\FatalErrorException;
|
||||
use Symfony\Component\Debug\FatalErrorHandler\UndefinedFunctionFatalErrorHandler;
|
||||
|
||||
class UndefinedFunctionFatalErrorHandlerTest extends \PHPUnit_Framework_TestCase
|
||||
class UndefinedFunctionFatalErrorHandlerTest extends TestCase
|
||||
{
|
||||
/**
|
||||
* @dataProvider provideUndefinedFunctionData
|
||||
|
||||
@@ -11,10 +11,11 @@
|
||||
|
||||
namespace Symfony\Component\Debug\Tests\FatalErrorHandler;
|
||||
|
||||
use PHPUnit\Framework\TestCase;
|
||||
use Symfony\Component\Debug\Exception\FatalErrorException;
|
||||
use Symfony\Component\Debug\FatalErrorHandler\UndefinedMethodFatalErrorHandler;
|
||||
|
||||
class UndefinedMethodFatalErrorHandlerTest extends \PHPUnit_Framework_TestCase
|
||||
class UndefinedMethodFatalErrorHandlerTest extends TestCase
|
||||
{
|
||||
/**
|
||||
* @dataProvider provideUndefinedMethodData
|
||||
@@ -61,6 +62,15 @@ class UndefinedMethodFatalErrorHandlerTest extends \PHPUnit_Framework_TestCase
|
||||
),
|
||||
"Attempted to call an undefined method named \"offsetFet\" of class \"SplObjectStorage\".\nDid you mean to call e.g. \"offsetGet\", \"offsetSet\" or \"offsetUnset\"?",
|
||||
),
|
||||
array(
|
||||
array(
|
||||
'type' => 1,
|
||||
'message' => 'Call to undefined method class@anonymous::test()',
|
||||
'file' => '/home/possum/work/symfony/test.php',
|
||||
'line' => 11,
|
||||
),
|
||||
'Attempted to call an undefined method named "test" of class "class@anonymous".',
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
7
Tests/Fixtures/NonDeprecatedInterface.php
Normal file
7
Tests/Fixtures/NonDeprecatedInterface.php
Normal file
@@ -0,0 +1,7 @@
|
||||
<?php
|
||||
|
||||
namespace Symfony\Component\Debug\Tests\Fixtures;
|
||||
|
||||
interface NonDeprecatedInterface extends DeprecatedInterface
|
||||
{
|
||||
}
|
||||
@@ -13,7 +13,7 @@ namespace Symfony\Component\Debug\Tests;
|
||||
|
||||
use Symfony\Component\Debug\ExceptionHandler;
|
||||
|
||||
class MockExceptionHandler extends Exceptionhandler
|
||||
class MockExceptionHandler extends ExceptionHandler
|
||||
{
|
||||
public $e;
|
||||
|
||||
|
||||
@@ -16,15 +16,15 @@
|
||||
}
|
||||
],
|
||||
"require": {
|
||||
"php": ">=5.5.9",
|
||||
"php": ">=5.3.9",
|
||||
"psr/log": "~1.0"
|
||||
},
|
||||
"conflict": {
|
||||
"symfony/http-kernel": ">=2.3,<2.3.24|~2.4.0|>=2.5,<2.5.9|>=2.6,<2.6.2"
|
||||
},
|
||||
"require-dev": {
|
||||
"symfony/class-loader": "~2.8|~3.0",
|
||||
"symfony/http-kernel": "~2.8|~3.0"
|
||||
"symfony/class-loader": "~2.2|~3.0.0",
|
||||
"symfony/http-kernel": "~2.3.24|~2.5.9|^2.6.2|~3.0.0"
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": { "Symfony\\Component\\Debug\\": "" },
|
||||
@@ -35,7 +35,7 @@
|
||||
"minimum-stability": "dev",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "3.0-dev"
|
||||
"dev-master": "2.8-dev"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user