mirror of
https://github.com/symfony/debug.git
synced 2026-03-25 09:42:20 +01:00
Compare commits
24 Commits
3.1
...
v3.2.0-BET
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e6688db8d9 | ||
|
|
61de488341 | ||
|
|
767b64d3c3 | ||
|
|
122391f692 | ||
|
|
027685d68d | ||
|
|
555e2aadbb | ||
|
|
7ad9b6d93e | ||
|
|
20295a8e78 | ||
|
|
54218143b7 | ||
|
|
e7e6cb50a9 | ||
|
|
b5a21674d4 | ||
|
|
6019275316 | ||
|
|
7bb15c20c1 | ||
|
|
697c527acd | ||
|
|
081a5659f7 | ||
|
|
7bd1a604be | ||
|
|
0abd031b28 | ||
|
|
f387801cf7 | ||
|
|
d1e2e0198b | ||
|
|
7e874063d9 | ||
|
|
28ce1b215a | ||
|
|
6ea446df0d | ||
|
|
ccdd60685b | ||
|
|
7f932c4349 |
@@ -1,6 +1,13 @@
|
||||
CHANGELOG
|
||||
=========
|
||||
|
||||
3.2.0
|
||||
-----
|
||||
|
||||
* `FlattenException::getTrace()` now returns additional type descriptions
|
||||
`integer` and `float`.
|
||||
|
||||
|
||||
3.0.0
|
||||
-----
|
||||
|
||||
|
||||
124
ErrorHandler.php
124
ErrorHandler.php
@@ -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,6 +44,7 @@ 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
|
||||
{
|
||||
@@ -87,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;
|
||||
@@ -146,6 +148,8 @@ class ErrorHandler
|
||||
$this->bootstrappingLogger = $bootstrappingLogger;
|
||||
$this->setDefaultLogger($bootstrappingLogger);
|
||||
}
|
||||
$this->traceReflector = new \ReflectionProperty('Exception', 'trace');
|
||||
$this->traceReflector->setAccessible(true);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -221,7 +225,7 @@ class ErrorHandler
|
||||
|
||||
if ($flush) {
|
||||
foreach ($this->bootstrappingLogger->cleanLogs() as $log) {
|
||||
$type = $log[2]['type'];
|
||||
$type = $log[2]['exception']->getSeverity();
|
||||
if (!isset($flush[$type])) {
|
||||
$this->bootstrappingLogger->log($log[0], $log[1], $log[2]);
|
||||
} elseif ($this->loggers[$type][0]) {
|
||||
@@ -363,6 +367,8 @@ class ErrorHandler
|
||||
*/
|
||||
public function handleError($type, $message, $file, $line, array $context, array $backtrace = null)
|
||||
{
|
||||
// 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;
|
||||
@@ -381,19 +387,44 @@ class ErrorHandler
|
||||
return true;
|
||||
}
|
||||
|
||||
if ($throw) {
|
||||
if (null !== self::$toStringException) {
|
||||
$throw = self::$toStringException;
|
||||
self::$toStringException = null;
|
||||
} elseif (($this->scopedErrors & $type) && class_exists(ContextErrorException::class)) {
|
||||
$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)) {
|
||||
$errorAsException = new SilencedErrorContext($type, $file, $line);
|
||||
} else {
|
||||
if ($this->scopedErrors & $type) {
|
||||
$errorAsException = new ContextErrorException($logMessage, 0, $type, $file, $line, $context);
|
||||
} else {
|
||||
$throw = new \ErrorException($this->levels[$type].': '.$message, 0, $type, $file, $line);
|
||||
$errorAsException = new \ErrorException($logMessage, 0, $type, $file, $line);
|
||||
}
|
||||
|
||||
if (E_USER_ERROR & $type) {
|
||||
$backtrace = $backtrace ?: $throw->getTrace();
|
||||
// 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 = $backtrace;
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
if (!($throw || $this->scopedErrors & $type)) {
|
||||
for ($i = 0; isset($lightTrace[$i]); ++$i) {
|
||||
unset($lightTrace[$i]['args']);
|
||||
}
|
||||
}
|
||||
$this->traceReflector->setValue($errorAsException, $lightTrace);
|
||||
} else {
|
||||
$this->traceReflector->setValue($errorAsException, array());
|
||||
}
|
||||
}
|
||||
|
||||
if ($throw) {
|
||||
if (E_USER_ERROR & $type) {
|
||||
for ($i = 1; isset($backtrace[$i]); ++$i) {
|
||||
if (isset($backtrace[$i]['function'], $backtrace[$i]['type'], $backtrace[$i - 1]['function'])
|
||||
&& '__toString' === $backtrace[$i]['function']
|
||||
@@ -412,7 +443,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;
|
||||
@@ -423,7 +454,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;
|
||||
@@ -432,47 +463,23 @@ 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 ($this->scopedErrors & $type) {
|
||||
$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,
|
||||
array('exception' => $errorAsException),
|
||||
);
|
||||
} 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, array('exception' => $errorAsException));
|
||||
} finally {
|
||||
$this->isRecursive = false;
|
||||
}
|
||||
@@ -497,20 +504,13 @@ class ErrorHandler
|
||||
$type = $exception instanceof FatalErrorException ? $exception->getSeverity() : E_ERROR;
|
||||
|
||||
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();
|
||||
@@ -525,7 +525,7 @@ class ErrorHandler
|
||||
}
|
||||
}
|
||||
if ($this->loggedErrors & $type) {
|
||||
$this->loggers[$type][0]->log($this->loggers[$type][1], $message, $e);
|
||||
$this->loggers[$type][0]->log($this->loggers[$type][1], $message, array('exception' => $exception));
|
||||
}
|
||||
if ($exception instanceof FatalErrorException && !$exception instanceof OutOfMemoryException && $error) {
|
||||
foreach ($this->getFatalErrorHandlers() as $handler) {
|
||||
@@ -631,10 +631,10 @@ class ErrorHandler
|
||||
$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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -642,8 +642,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]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -237,6 +237,10 @@ class FlattenException
|
||||
$result[$key] = array('null', null);
|
||||
} elseif (is_bool($value)) {
|
||||
$result[$key] = array('boolean', $value);
|
||||
} elseif (is_integer($value)) {
|
||||
$result[$key] = array('integer', $value);
|
||||
} elseif (is_float($value)) {
|
||||
$result[$key] = array('float', $value);
|
||||
} elseif (is_resource($value)) {
|
||||
$result[$key] = array('resource', get_resource_type($value));
|
||||
} else {
|
||||
|
||||
55
Exception/SilencedErrorContext.php
Normal file
55
Exception/SilencedErrorContext.php
Normal file
@@ -0,0 +1,55 @@
|
||||
<?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;
|
||||
|
||||
/**
|
||||
* Data Object that represents a Silenced Error.
|
||||
*
|
||||
* @author Grégoire Pineau <lyrixx@lyrixx.info>
|
||||
*/
|
||||
class SilencedErrorContext implements \JsonSerializable
|
||||
{
|
||||
private $severity;
|
||||
private $file;
|
||||
private $line;
|
||||
|
||||
public function __construct($severity, $file, $line)
|
||||
{
|
||||
$this->severity = $severity;
|
||||
$this->file = $file;
|
||||
$this->line = $line;
|
||||
}
|
||||
|
||||
public function getSeverity()
|
||||
{
|
||||
return $this->severity;
|
||||
}
|
||||
|
||||
public function getFile()
|
||||
{
|
||||
return $this->file;
|
||||
}
|
||||
|
||||
public function getLine()
|
||||
{
|
||||
return $this->line;
|
||||
}
|
||||
|
||||
public function JsonSerialize()
|
||||
{
|
||||
return array(
|
||||
'severity' => $this->severity,
|
||||
'file' => $this->file,
|
||||
'line' => $this->line,
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -13,6 +13,7 @@ namespace Symfony\Component\Debug;
|
||||
|
||||
use Symfony\Component\Debug\Exception\FlattenException;
|
||||
use Symfony\Component\Debug\Exception\OutOfMemoryException;
|
||||
use Symfony\Component\HttpKernel\Debug\FileLinkFormatter;
|
||||
|
||||
/**
|
||||
* ExceptionHandler converts an exception to a Response object.
|
||||
@@ -82,14 +83,14 @@ class ExceptionHandler
|
||||
/**
|
||||
* Sets the format for links to source files.
|
||||
*
|
||||
* @param string $format The format for links to source files
|
||||
* @param string|FileLinkFormatter $format The format for links to source files
|
||||
*
|
||||
* @return string The previous file link format
|
||||
*/
|
||||
public function setFileLinkFormat($format)
|
||||
public function setFileLinkFormat($fileLinkFormat)
|
||||
{
|
||||
$old = $this->fileLinkFormat;
|
||||
$this->fileLinkFormat = $format;
|
||||
$this->fileLinkFormat = $fileLinkFormat;
|
||||
|
||||
return $old;
|
||||
}
|
||||
@@ -290,10 +291,6 @@ EOF;
|
||||
.sf-reset .exception_message { margin-left: 3em; display: block; }
|
||||
.sf-reset .traces li { font-size:12px; padding: 2px 4px; list-style-type:decimal; margin-left:20px; }
|
||||
.sf-reset .block { background-color:#FFFFFF; padding:10px 28px; margin-bottom:20px;
|
||||
-webkit-border-bottom-right-radius: 16px;
|
||||
-webkit-border-bottom-left-radius: 16px;
|
||||
-moz-border-radius-bottomright: 16px;
|
||||
-moz-border-radius-bottomleft: 16px;
|
||||
border-bottom-right-radius: 16px;
|
||||
border-bottom-left-radius: 16px;
|
||||
border-bottom:1px solid #ccc;
|
||||
@@ -302,10 +299,6 @@ EOF;
|
||||
word-wrap: break-word;
|
||||
}
|
||||
.sf-reset .block_exception { background-color:#ddd; color: #333; padding:20px;
|
||||
-webkit-border-top-left-radius: 16px;
|
||||
-webkit-border-top-right-radius: 16px;
|
||||
-moz-border-radius-topleft: 16px;
|
||||
-moz-border-radius-topright: 16px;
|
||||
border-top-left-radius: 16px;
|
||||
border-top-right-radius: 16px;
|
||||
border-top:1px solid #ccc;
|
||||
@@ -318,8 +311,6 @@ EOF;
|
||||
.sf-reset a:hover { background:none; color:#313131; text-decoration:underline; }
|
||||
.sf-reset ol { padding: 10px 0; }
|
||||
.sf-reset h1 { background-color:#FFFFFF; padding: 15px 28px; margin-bottom: 20px;
|
||||
-webkit-border-radius: 10px;
|
||||
-moz-border-radius: 10px;
|
||||
border-radius: 10px;
|
||||
border: 1px solid #ccc;
|
||||
}
|
||||
@@ -344,7 +335,7 @@ EOF;
|
||||
$css
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<body ondblclick="var t = event.target; if (t.title && !t.href) { var f = t.innerHTML; t.innerHTML = t.title; t.title = f; }">
|
||||
$content
|
||||
</body>
|
||||
</html>
|
||||
@@ -360,16 +351,14 @@ EOF;
|
||||
|
||||
private function formatPath($path, $line)
|
||||
{
|
||||
$path = $this->escapeHtml($path);
|
||||
$file = preg_match('#[^/\\\\]*$#', $path, $file) ? $file[0] : $path;
|
||||
$file = $this->escapeHtml(preg_match('#[^/\\\\]*+$#', $path, $file) ? $file[0] : $path);
|
||||
$fmt = $this->fileLinkFormat;
|
||||
|
||||
if ($linkFormat = $this->fileLinkFormat) {
|
||||
$link = strtr($this->escapeHtml($linkFormat), array('%f' => $path, '%l' => (int) $line));
|
||||
|
||||
return sprintf(' in <a href="%s" title="Go to source">%s line %d</a>', $link, $file, $line);
|
||||
if ($fmt && $link = is_string($fmt) ? strtr($fmt, array('%f' => $path, '%l' => $line)) : $fmt->format($path, $line)) {
|
||||
return sprintf(' in <a href="%s" title="Go to source">%s line %d</a>', $this->escapeHtml($link), $file, $line);
|
||||
}
|
||||
|
||||
return sprintf(' in <a title="%s line %3$d" ondblclick="var f=this.innerHTML;this.innerHTML=this.title;this.title=f;">%s line %d</a>', $path, $file, $line);
|
||||
return sprintf(' in <a title="%s line %3$d">%s line %d</a>', $this->escapeHtml($path), $file, $line);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -387,8 +376,6 @@ EOF;
|
||||
$formattedValue = sprintf('<em>object</em>(%s)', $this->formatClass($item[1]));
|
||||
} elseif ('array' === $item[0]) {
|
||||
$formattedValue = sprintf('<em>array</em>(%s)', is_array($item[1]) ? $this->formatArgs($item[1]) : $item[1]);
|
||||
} elseif ('string' === $item[0]) {
|
||||
$formattedValue = sprintf("'%s'", $this->escapeHtml($item[1]));
|
||||
} elseif ('null' === $item[0]) {
|
||||
$formattedValue = '<em>null</em>';
|
||||
} elseif ('boolean' === $item[0]) {
|
||||
@@ -396,7 +383,7 @@ EOF;
|
||||
} elseif ('resource' === $item[0]) {
|
||||
$formattedValue = '<em>resource</em>';
|
||||
} else {
|
||||
$formattedValue = str_replace("\n", '', var_export($this->escapeHtml((string) $item[1]), true));
|
||||
$formattedValue = str_replace("\n", '', $this->escapeHtml(var_export($item[1], true)));
|
||||
}
|
||||
|
||||
$result[] = is_int($key) ? $formattedValue : sprintf("'%s' => %s", $key, $formattedValue);
|
||||
@@ -410,6 +397,6 @@ EOF;
|
||||
*/
|
||||
private function escapeHtml($str)
|
||||
{
|
||||
return htmlspecialchars($str, ENT_QUOTES | ENT_SUBSTITUTE, $this->charset);
|
||||
return htmlspecialchars($str, ENT_COMPAT | ENT_SUBSTITUTE, $this->charset);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,9 +12,10 @@
|
||||
namespace Symfony\Component\Debug\Tests;
|
||||
|
||||
use Psr\Log\LogLevel;
|
||||
use Symfony\Component\Debug\ErrorHandler;
|
||||
use Symfony\Component\Debug\BufferingLogger;
|
||||
use Symfony\Component\Debug\ErrorHandler;
|
||||
use Symfony\Component\Debug\Exception\ContextErrorException;
|
||||
use Symfony\Component\Debug\Exception\SilencedErrorContext;
|
||||
|
||||
/**
|
||||
* ErrorHandlerTest.
|
||||
@@ -79,20 +80,16 @@ class ErrorHandlerTest extends \PHPUnit_Framework_TestCase
|
||||
$this->assertArrayHasKey('foobar', $exception->getContext());
|
||||
|
||||
$trace = $exception->getTrace();
|
||||
|
||||
$this->assertEquals(__FILE__, $trace[0]['file']);
|
||||
$this->assertEquals('Symfony\Component\Debug\ErrorHandler', $trace[0]['class']);
|
||||
$this->assertEquals('handleError', $trace[0]['function']);
|
||||
$this->assertEquals('->', $trace[0]['type']);
|
||||
$this->assertEquals(__CLASS__, $trace[0]['class']);
|
||||
$this->assertEquals('triggerNotice', $trace[0]['function']);
|
||||
$this->assertEquals('::', $trace[0]['type']);
|
||||
|
||||
$this->assertEquals(__FILE__, $trace[1]['file']);
|
||||
$this->assertEquals(__FILE__, $trace[0]['file']);
|
||||
$this->assertEquals(__CLASS__, $trace[1]['class']);
|
||||
$this->assertEquals('triggerNotice', $trace[1]['function']);
|
||||
$this->assertEquals('::', $trace[1]['type']);
|
||||
|
||||
$this->assertEquals(__FILE__, $trace[1]['file']);
|
||||
$this->assertEquals(__CLASS__, $trace[2]['class']);
|
||||
$this->assertEquals(__FUNCTION__, $trace[2]['function']);
|
||||
$this->assertEquals('->', $trace[2]['type']);
|
||||
$this->assertEquals(__FUNCTION__, $trace[1]['function']);
|
||||
$this->assertEquals('->', $trace[1]['type']);
|
||||
} finally {
|
||||
restore_error_handler();
|
||||
restore_exception_handler();
|
||||
@@ -202,11 +199,12 @@ class ErrorHandlerTest extends \PHPUnit_Framework_TestCase
|
||||
|
||||
$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']);
|
||||
$this->assertEquals('User Deprecated: foo', $message);
|
||||
$this->assertArrayHasKey('exception', $context);
|
||||
$exception = $context['exception'];
|
||||
$this->assertInstanceOf(\ErrorException::class, $exception);
|
||||
$this->assertSame('User Deprecated: foo', $exception->getMessage());
|
||||
$this->assertSame(E_USER_DEPRECATED, $exception->getSeverity());
|
||||
};
|
||||
|
||||
$logger
|
||||
@@ -225,9 +223,11 @@ class ErrorHandlerTest extends \PHPUnit_Framework_TestCase
|
||||
$logger = $this->getMock('Psr\Log\LoggerInterface');
|
||||
|
||||
$logArgCheck = function ($level, $message, $context) {
|
||||
$this->assertEquals('Undefined variable: undefVar', $message);
|
||||
$this->assertArrayHasKey('type', $context);
|
||||
$this->assertEquals($context['type'], E_NOTICE);
|
||||
$this->assertEquals('Notice: Undefined variable: undefVar', $message);
|
||||
$this->assertArrayHasKey('exception', $context);
|
||||
$exception = $context['exception'];
|
||||
$this->assertInstanceOf(SilencedErrorContext::class, $exception);
|
||||
$this->assertSame(E_NOTICE, $exception->getSeverity());
|
||||
};
|
||||
|
||||
$logger
|
||||
@@ -278,9 +278,10 @@ class ErrorHandlerTest extends \PHPUnit_Framework_TestCase
|
||||
{
|
||||
$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);
|
||||
$this->assertArrayHasKey('exception', $context);
|
||||
$exception = $context['exception'];
|
||||
$this->assertInstanceOf(\ErrorException::class, $exception);
|
||||
$this->assertSame('User Deprecated: Foo deprecation', $exception->getMessage());
|
||||
};
|
||||
|
||||
$logger = $this->getMock('Psr\Log\LoggerInterface');
|
||||
@@ -305,9 +306,9 @@ class ErrorHandlerTest extends \PHPUnit_Framework_TestCase
|
||||
$logger = $this->getMock('Psr\Log\LoggerInterface');
|
||||
|
||||
$logArgCheck = function ($level, $message, $context) {
|
||||
$this->assertEquals('Uncaught Exception: foo', $message);
|
||||
$this->assertArrayHasKey('type', $context);
|
||||
$this->assertEquals($context['type'], E_ERROR);
|
||||
$this->assertSame('Uncaught Exception: foo', $message);
|
||||
$this->assertArrayHasKey('exception', $context);
|
||||
$this->assertInstanceOf(\Exception::class, $context['exception']);
|
||||
};
|
||||
|
||||
$logger
|
||||
@@ -349,7 +350,7 @@ class ErrorHandlerTest extends \PHPUnit_Framework_TestCase
|
||||
->method('log')
|
||||
->withConsecutive(
|
||||
array($this->equalTo(LogLevel::WARNING), $this->equalTo('Dummy log')),
|
||||
array($this->equalTo(LogLevel::DEBUG), $this->equalTo('Silenced warning'))
|
||||
array($this->equalTo(LogLevel::DEBUG), $this->equalTo('User Warning: Silenced warning'))
|
||||
)
|
||||
;
|
||||
|
||||
@@ -391,19 +392,27 @@ class ErrorHandlerTest extends \PHPUnit_Framework_TestCase
|
||||
$this->assertSame($loggers, $handler->setLoggers(array()));
|
||||
|
||||
$handler->handleError(E_DEPRECATED, 'Foo message', __FILE__, 123, array());
|
||||
$expectedLog = array(LogLevel::INFO, 'Foo message', array('type' => E_DEPRECATED, 'file' => __FILE__, 'line' => 123, 'level' => error_reporting()));
|
||||
|
||||
$logs = $bootLogger->cleanLogs();
|
||||
unset($logs[0][2]['stack']);
|
||||
|
||||
$this->assertSame(array($expectedLog), $logs);
|
||||
$this->assertCount(1, $logs);
|
||||
$log = $logs[0];
|
||||
$this->assertSame('info', $log[0]);
|
||||
$this->assertSame('Deprecated: Foo message', $log[1]);
|
||||
$this->assertArrayHasKey('exception', $log[2]);
|
||||
$exception = $log[2]['exception'];
|
||||
$this->assertInstanceOf(\ErrorException::class, $exception);
|
||||
$this->assertSame('Deprecated: Foo message', $exception->getMessage());
|
||||
$this->assertSame(__FILE__, $exception->getFile());
|
||||
$this->assertSame(123, $exception->getLine());
|
||||
$this->assertSame(E_DEPRECATED, $exception->getSeverity());
|
||||
|
||||
$bootLogger->log($expectedLog[0], $expectedLog[1], $expectedLog[2]);
|
||||
$bootLogger->log(LogLevel::WARNING, 'Foo message', array('exception' => $exception));
|
||||
|
||||
$mockLogger = $this->getMock('Psr\Log\LoggerInterface');
|
||||
$mockLogger->expects($this->once())
|
||||
->method('log')
|
||||
->with(LogLevel::WARNING, 'Foo message', $expectedLog[2]);
|
||||
->with(LogLevel::WARNING, 'Foo message', array('exception' => $exception));
|
||||
|
||||
$handler->setLoggers(array(E_DEPRECATED => array($mockLogger, LogLevel::WARNING)));
|
||||
}
|
||||
@@ -424,8 +433,8 @@ class ErrorHandlerTest extends \PHPUnit_Framework_TestCase
|
||||
|
||||
$logArgCheck = function ($level, $message, $context) {
|
||||
$this->assertEquals('Fatal Parse Error: foo', $message);
|
||||
$this->assertArrayHasKey('type', $context);
|
||||
$this->assertEquals($context['type'], E_PARSE);
|
||||
$this->assertArrayHasKey('exception', $context);
|
||||
$this->assertInstanceOf(\Exception::class, $context['exception']);
|
||||
};
|
||||
|
||||
$logger
|
||||
@@ -477,14 +486,7 @@ class ErrorHandlerTest extends \PHPUnit_Framework_TestCase
|
||||
->method('log')
|
||||
->with(
|
||||
$this->equalTo(LogLevel::CRITICAL),
|
||||
$this->equalTo('Fatal Error: foo'),
|
||||
$this->equalTo(array(
|
||||
'type' => 1,
|
||||
'file' => 'bar',
|
||||
'line' => 123,
|
||||
'level' => -1,
|
||||
'stack' => array(456),
|
||||
))
|
||||
$this->equalTo('Fatal Error: foo')
|
||||
)
|
||||
;
|
||||
|
||||
|
||||
@@ -190,6 +190,68 @@ class FlattenExceptionTest extends \PHPUnit_Framework_TestCase
|
||||
);
|
||||
}
|
||||
|
||||
public function testArguments()
|
||||
{
|
||||
$dh = opendir(__DIR__);
|
||||
$fh = tmpfile();
|
||||
|
||||
$incomplete = unserialize('O:14:"BogusTestClass":0:{}');
|
||||
|
||||
$exception = $this->createException(array(
|
||||
(object) array('foo' => 1),
|
||||
new NotFoundHttpException(),
|
||||
$incomplete,
|
||||
$dh,
|
||||
$fh,
|
||||
function () {},
|
||||
array(1, 2),
|
||||
array('foo' => 123),
|
||||
null,
|
||||
true,
|
||||
false,
|
||||
0,
|
||||
0.0,
|
||||
'0',
|
||||
'',
|
||||
INF,
|
||||
NAN,
|
||||
));
|
||||
|
||||
$flattened = FlattenException::create($exception);
|
||||
$trace = $flattened->getTrace();
|
||||
$args = $trace[1]['args'];
|
||||
$array = $args[0][1];
|
||||
|
||||
closedir($dh);
|
||||
fclose($fh);
|
||||
|
||||
$i = 0;
|
||||
$this->assertSame(array('object', 'stdClass'), $array[$i++]);
|
||||
$this->assertSame(array('object', 'Symfony\Component\HttpKernel\Exception\NotFoundHttpException'), $array[$i++]);
|
||||
$this->assertSame(array('incomplete-object', 'BogusTestClass'), $array[$i++]);
|
||||
$this->assertSame(array('resource', defined('HHVM_VERSION') ? 'Directory' : 'stream'), $array[$i++]);
|
||||
$this->assertSame(array('resource', 'stream'), $array[$i++]);
|
||||
|
||||
$args = $array[$i++];
|
||||
$this->assertSame($args[0], 'object');
|
||||
$this->assertTrue('Closure' === $args[1] || is_subclass_of($args[1], '\Closure'), 'Expect object class name to be Closure or a subclass of Closure.');
|
||||
|
||||
$this->assertSame(array('array', array(array('integer', 1), array('integer', 2))), $array[$i++]);
|
||||
$this->assertSame(array('array', array('foo' => array('integer', 123))), $array[$i++]);
|
||||
$this->assertSame(array('null', null), $array[$i++]);
|
||||
$this->assertSame(array('boolean', true), $array[$i++]);
|
||||
$this->assertSame(array('boolean', false), $array[$i++]);
|
||||
$this->assertSame(array('integer', 0), $array[$i++]);
|
||||
$this->assertSame(array('float', 0.0), $array[$i++]);
|
||||
$this->assertSame(array('string', '0'), $array[$i++]);
|
||||
$this->assertSame(array('string', ''), $array[$i++]);
|
||||
$this->assertSame(array('float', INF), $array[$i++]);
|
||||
|
||||
// assertEquals() does not like NAN values.
|
||||
$this->assertEquals($array[$i][0], 'float');
|
||||
$this->assertTrue(is_nan($array[$i++][1]));
|
||||
}
|
||||
|
||||
public function testRecursionInArguments()
|
||||
{
|
||||
$a = array('foo', array(2, &$a));
|
||||
@@ -216,6 +278,9 @@ class FlattenExceptionTest extends \PHPUnit_Framework_TestCase
|
||||
|
||||
$flattened = FlattenException::create($exception);
|
||||
$trace = $flattened->getTrace();
|
||||
|
||||
$this->assertSame($trace[1]['args'][0], array('array', array('array', '*SKIPPED over 10000 entries*')));
|
||||
|
||||
$serializeTrace = serialize($trace);
|
||||
|
||||
$this->assertContains('*SKIPPED over 10000 entries*', $serializeTrace);
|
||||
@@ -226,45 +291,4 @@ class FlattenExceptionTest extends \PHPUnit_Framework_TestCase
|
||||
{
|
||||
return new \Exception();
|
||||
}
|
||||
|
||||
public function testSetTraceIncompleteClass()
|
||||
{
|
||||
$flattened = FlattenException::create(new \Exception('test', 123));
|
||||
$flattened->setTrace(
|
||||
array(
|
||||
array(
|
||||
'file' => __FILE__,
|
||||
'line' => 123,
|
||||
'function' => 'test',
|
||||
'args' => array(
|
||||
unserialize('O:14:"BogusTestClass":0:{}'),
|
||||
),
|
||||
),
|
||||
),
|
||||
'foo.php', 123
|
||||
);
|
||||
|
||||
$this->assertEquals(array(
|
||||
array(
|
||||
'message' => 'test',
|
||||
'class' => 'Exception',
|
||||
'trace' => array(
|
||||
array(
|
||||
'namespace' => '', 'short_class' => '', 'class' => '', 'type' => '', 'function' => '',
|
||||
'file' => 'foo.php', 'line' => 123,
|
||||
'args' => array(),
|
||||
),
|
||||
array(
|
||||
'namespace' => '', 'short_class' => '', 'class' => '', 'type' => '', 'function' => 'test',
|
||||
'file' => __FILE__, 'line' => 123,
|
||||
'args' => array(
|
||||
array(
|
||||
'incomplete-object', 'BogusTestClass',
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
), $flattened->toArray());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -35,7 +35,7 @@
|
||||
"minimum-stability": "dev",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "3.1-dev"
|
||||
"dev-master": "3.2-dev"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user