mirror of
https://github.com/symfony/debug.git
synced 2026-03-24 17:22:13 +01:00
Compare commits
60 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
30d1de52f1 | ||
|
|
dfe71c73cf | ||
|
|
8bc9390ba3 | ||
|
|
95a5aa2b72 | ||
|
|
9cd1287f00 | ||
|
|
01c8bc9bac | ||
|
|
796dd4cd11 | ||
|
|
3e889e0489 | ||
|
|
dfb9bf2e04 | ||
|
|
29a6fd38f3 | ||
|
|
712c58246b | ||
|
|
4ba2bda995 | ||
|
|
24170a0eb7 | ||
|
|
b7c4104ea0 | ||
|
|
ee29381719 | ||
|
|
028a28b024 | ||
|
|
6e5c2b9e1f | ||
|
|
bc5a43ca7c | ||
|
|
0021c1d0d2 | ||
|
|
86497902eb | ||
|
|
e6c079c4c1 | ||
|
|
62ebdfc7d6 | ||
|
|
7a2e2e7580 | ||
|
|
3db261c0bd | ||
|
|
de91f9cf14 | ||
|
|
a331253db6 | ||
|
|
1164432942 | ||
|
|
1c5c246195 | ||
|
|
49c9cb8adc | ||
|
|
542c721438 | ||
|
|
d492ff8385 | ||
|
|
5a7ebac6ac | ||
|
|
d854bf96fe | ||
|
|
342b4e4a8e | ||
|
|
883f847ad1 | ||
|
|
9760bae845 | ||
|
|
993f4c9cfc | ||
|
|
91e3a1480c | ||
|
|
732b41060b | ||
|
|
ca764f8af9 | ||
|
|
9fb191fa62 | ||
|
|
b2e922174d | ||
|
|
bdfb718a6c | ||
|
|
3c1b5f218d | ||
|
|
78dc94dce6 | ||
|
|
4885c636af | ||
|
|
6a55635898 | ||
|
|
7f875d2aae | ||
|
|
13d5fe432f | ||
|
|
89151cc3fe | ||
|
|
93f26330c7 | ||
|
|
b4ea949b41 | ||
|
|
264eb40f8d | ||
|
|
ff1f1fc483 | ||
|
|
5da7e8c937 | ||
|
|
085d4fd990 | ||
|
|
7f671456b9 | ||
|
|
234f31cd20 | ||
|
|
729f6d19cf | ||
|
|
947e8d434b |
@@ -30,8 +30,8 @@ class Debug
|
||||
* If the Symfony ClassLoader component is available, a special
|
||||
* class loader is also registered.
|
||||
*
|
||||
* @param integer $errorReportingLevel The level of error reporting you want
|
||||
* @param Boolean $displayErrors Whether to display errors (for development) or just log them (for production)
|
||||
* @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 = null, $displayErrors = true)
|
||||
{
|
||||
|
||||
@@ -13,6 +13,7 @@ namespace Symfony\Component\Debug;
|
||||
|
||||
use Symfony\Component\Debug\Exception\FatalErrorException;
|
||||
use Symfony\Component\Debug\Exception\ContextErrorException;
|
||||
use Symfony\Component\Debug\Exception\DummyException;
|
||||
use Psr\Log\LoggerInterface;
|
||||
|
||||
/**
|
||||
@@ -26,19 +27,19 @@ class ErrorHandler
|
||||
const TYPE_DEPRECATION = -100;
|
||||
|
||||
private $levels = array(
|
||||
E_WARNING => 'Warning',
|
||||
E_NOTICE => 'Notice',
|
||||
E_USER_ERROR => 'User Error',
|
||||
E_USER_WARNING => 'User Warning',
|
||||
E_USER_NOTICE => 'User Notice',
|
||||
E_STRICT => 'Runtime Notice',
|
||||
E_WARNING => 'Warning',
|
||||
E_NOTICE => 'Notice',
|
||||
E_USER_ERROR => 'User Error',
|
||||
E_USER_WARNING => 'User Warning',
|
||||
E_USER_NOTICE => 'User Notice',
|
||||
E_STRICT => 'Runtime Notice',
|
||||
E_RECOVERABLE_ERROR => 'Catchable Fatal Error',
|
||||
E_DEPRECATED => 'Deprecated',
|
||||
E_USER_DEPRECATED => 'User Deprecated',
|
||||
E_ERROR => 'Error',
|
||||
E_CORE_ERROR => 'Core Error',
|
||||
E_COMPILE_ERROR => 'Compile Error',
|
||||
E_PARSE => 'Parse',
|
||||
E_DEPRECATED => 'Deprecated',
|
||||
E_USER_DEPRECATED => 'User Deprecated',
|
||||
E_ERROR => 'Error',
|
||||
E_CORE_ERROR => 'Core Error',
|
||||
E_COMPILE_ERROR => 'Compile Error',
|
||||
E_PARSE => 'Parse',
|
||||
);
|
||||
|
||||
private $level;
|
||||
@@ -55,10 +56,10 @@ class ErrorHandler
|
||||
/**
|
||||
* Registers the error handler.
|
||||
*
|
||||
* @param integer $level The level at which the conversion to Exception is done (null to use the error_reporting() value and 0 to disable)
|
||||
* @param Boolean $displayErrors Display errors (for dev environment) or just log they (production usage)
|
||||
* @param int $level The level at which the conversion to Exception is done (null to use the error_reporting() value and 0 to disable)
|
||||
* @param bool $displayErrors Display errors (for dev environment) or just log they (production usage)
|
||||
*
|
||||
* @return The registered error handler
|
||||
* @return ErrorHandler The registered error handler
|
||||
*/
|
||||
public static function register($level = null, $displayErrors = true)
|
||||
{
|
||||
@@ -100,10 +101,11 @@ class ErrorHandler
|
||||
|
||||
if ($level & (E_USER_DEPRECATED | E_DEPRECATED)) {
|
||||
if (isset(self::$loggers['deprecation'])) {
|
||||
if (version_compare(PHP_VERSION, '5.4', '<')) {
|
||||
if (PHP_VERSION_ID < 50400) {
|
||||
$stack = array_map(
|
||||
function ($row) {
|
||||
unset($row['args']);
|
||||
|
||||
return $row;
|
||||
},
|
||||
array_slice(debug_backtrace(false), 0, 10)
|
||||
@@ -119,7 +121,46 @@ class ErrorHandler
|
||||
}
|
||||
|
||||
if ($this->displayErrors && error_reporting() & $level && $this->level & $level) {
|
||||
throw new ContextErrorException(sprintf('%s: %s in %s line %d', isset($this->levels[$level]) ? $this->levels[$level] : $level, $message, $file, $line), 0, $level, $file, $line, $context);
|
||||
// make sure the ContextErrorException class is loaded (https://bugs.php.net/bug.php?id=65322)
|
||||
if (!class_exists('Symfony\Component\Debug\Exception\ContextErrorException')) {
|
||||
require __DIR__.'/Exception/ContextErrorException.php';
|
||||
}
|
||||
if (!class_exists('Symfony\Component\Debug\Exception\FlattenException')) {
|
||||
require __DIR__.'/Exception/FlattenException.php';
|
||||
}
|
||||
|
||||
if (PHP_VERSION_ID < 50400 && isset($context['GLOBALS']) && is_array($context)) {
|
||||
unset($context['GLOBALS']);
|
||||
}
|
||||
|
||||
$exception = new ContextErrorException(sprintf('%s: %s in %s line %d', isset($this->levels[$level]) ? $this->levels[$level] : $level, $message, $file, $line), 0, $level, $file, $line, $context);
|
||||
|
||||
// Exceptions thrown from error handlers are sometimes not caught by the exception
|
||||
// handler, so we invoke it directly (https://bugs.php.net/bug.php?id=54275)
|
||||
$exceptionHandler = set_exception_handler(function () {});
|
||||
restore_exception_handler();
|
||||
|
||||
if (is_array($exceptionHandler) && $exceptionHandler[0] instanceof ExceptionHandler) {
|
||||
$exceptionHandler[0]->handle($exception);
|
||||
|
||||
if (!class_exists('Symfony\Component\Debug\Exception\DummyException')) {
|
||||
require __DIR__.'/Exception/DummyException.php';
|
||||
}
|
||||
|
||||
// we must stop the PHP script execution, as the exception has
|
||||
// already been dealt with, so, let's throw an exception that
|
||||
// will be caught by a dummy exception handler
|
||||
set_exception_handler(function (\Exception $e) use ($exceptionHandler) {
|
||||
if (!$e instanceof DummyException) {
|
||||
// happens if our dummy exception is caught by a
|
||||
// catch-all from user code, in which case, let's the
|
||||
// current handler handle this "new" exception
|
||||
call_user_func($exceptionHandler, $e);
|
||||
}
|
||||
});
|
||||
|
||||
throw new DummyException();
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
@@ -131,7 +172,7 @@ class ErrorHandler
|
||||
return;
|
||||
}
|
||||
|
||||
unset($this->reservedMemory);
|
||||
$this->reservedMemory = '';
|
||||
$type = $error['type'];
|
||||
if (0 === $this->level || !in_array($type, array(E_ERROR, E_CORE_ERROR, E_COMPILE_ERROR, E_PARSE))) {
|
||||
return;
|
||||
@@ -152,7 +193,7 @@ class ErrorHandler
|
||||
}
|
||||
|
||||
// get current exception handler
|
||||
$exceptionHandler = set_exception_handler(function() {});
|
||||
$exceptionHandler = set_exception_handler(function () {});
|
||||
restore_exception_handler();
|
||||
|
||||
if (is_array($exceptionHandler) && $exceptionHandler[0] instanceof ExceptionHandler) {
|
||||
|
||||
@@ -19,18 +19,18 @@ namespace Symfony\Component\Debug\Exception;
|
||||
class ContextErrorException extends \ErrorException
|
||||
{
|
||||
private $context = array();
|
||||
|
||||
|
||||
public function __construct($message, $code, $severity, $filename, $lineno, $context = array())
|
||||
{
|
||||
parent::__construct($message, $code, $severity, $filename, $lineno);
|
||||
$this->context = $context;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return array Array of variables that existed when the exception occured
|
||||
* @return array Array of variables that existed when the exception occurred
|
||||
*/
|
||||
public function getContext()
|
||||
{
|
||||
return $this->context;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
21
Exception/DummyException.php
Normal file
21
Exception/DummyException.php
Normal file
@@ -0,0 +1,21 @@
|
||||
<?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;
|
||||
|
||||
/**
|
||||
* Used to stop execution of a PHP script after handling a fatal error.
|
||||
*
|
||||
* @author Fabien Potencier <fabien@symfony.com>
|
||||
*/
|
||||
class DummyException extends \ErrorException
|
||||
{
|
||||
}
|
||||
@@ -9,13 +9,28 @@
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\HttpKernel\Exception;
|
||||
|
||||
/**
|
||||
* Fatal Error Exception.
|
||||
*
|
||||
* @author Konstanton Myakshin <koc-dp@yandex.ru>
|
||||
*
|
||||
* @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
|
||||
{
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
@@ -66,8 +107,8 @@ class FlattenException
|
||||
foreach (array_merge(array($this), $this->getAllPrevious()) as $exception) {
|
||||
$exceptions[] = array(
|
||||
'message' => $exception->getMessage(),
|
||||
'class' => $exception->getClass(),
|
||||
'trace' => $exception->getTrace(),
|
||||
'class' => $exception->getClass(),
|
||||
'trace' => $exception->getTrace(),
|
||||
);
|
||||
}
|
||||
|
||||
@@ -208,14 +249,14 @@ class FlattenException
|
||||
{
|
||||
$this->trace = array();
|
||||
$this->trace[] = array(
|
||||
'namespace' => '',
|
||||
'namespace' => '',
|
||||
'short_class' => '',
|
||||
'class' => '',
|
||||
'type' => '',
|
||||
'function' => '',
|
||||
'file' => $file,
|
||||
'line' => $line,
|
||||
'args' => array(),
|
||||
'class' => '',
|
||||
'type' => '',
|
||||
'function' => '',
|
||||
'file' => $file,
|
||||
'line' => $line,
|
||||
'args' => array(),
|
||||
);
|
||||
foreach ($trace as $entry) {
|
||||
$class = '';
|
||||
@@ -227,29 +268,32 @@ class FlattenException
|
||||
}
|
||||
|
||||
$this->trace[] = array(
|
||||
'namespace' => $namespace,
|
||||
'namespace' => $namespace,
|
||||
'short_class' => $class,
|
||||
'class' => isset($entry['class']) ? $entry['class'] : '',
|
||||
'type' => isset($entry['type']) ? $entry['type'] : '',
|
||||
'function' => isset($entry['function']) ? $entry['function'] : null,
|
||||
'file' => isset($entry['file']) ? $entry['file'] : null,
|
||||
'line' => isset($entry['line']) ? $entry['line'] : null,
|
||||
'args' => isset($entry['args']) ? $this->flattenArgs($entry['args']) : array(),
|
||||
'class' => isset($entry['class']) ? $entry['class'] : '',
|
||||
'type' => isset($entry['type']) ? $entry['type'] : '',
|
||||
'function' => isset($entry['function']) ? $entry['function'] : null,
|
||||
'file' => isset($entry['file']) ? $entry['file'] : null,
|
||||
'line' => isset($entry['line']) ? $entry['line'] : null,
|
||||
'args' => isset($entry['args']) ? $this->flattenArgs($entry['args']) : array(),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
private function flattenArgs($args, $level = 0)
|
||||
private function flattenArgs($args, $level = 0, &$count = 0)
|
||||
{
|
||||
$result = array();
|
||||
foreach ($args as $key => $value) {
|
||||
if (++$count > 1e4) {
|
||||
return array('array', '*SKIPPED over 10000 entries*');
|
||||
}
|
||||
if (is_object($value)) {
|
||||
$result[$key] = array('object', get_class($value));
|
||||
} elseif (is_array($value)) {
|
||||
if ($level > 10) {
|
||||
$result[$key] = array('array', '*DEEP NESTED ARRAY*');
|
||||
} else {
|
||||
$result[$key] = array('array', $this->flattenArgs($value, ++$level));
|
||||
$result[$key] = array('array', $this->flattenArgs($value, $level + 1, $count));
|
||||
}
|
||||
} elseif (null === $value) {
|
||||
$result[$key] = array('null', null);
|
||||
|
||||
@@ -14,10 +14,6 @@ namespace Symfony\Component\Debug;
|
||||
use Symfony\Component\HttpFoundation\Response;
|
||||
use Symfony\Component\Debug\Exception\FlattenException;
|
||||
|
||||
if (!defined('ENT_SUBSTITUTE')) {
|
||||
define('ENT_SUBSTITUTE', 8);
|
||||
}
|
||||
|
||||
/**
|
||||
* ExceptionHandler converts an exception to a Response object.
|
||||
*
|
||||
@@ -43,7 +39,7 @@ class ExceptionHandler
|
||||
/**
|
||||
* Registers the exception handler.
|
||||
*
|
||||
* @param Boolean $debug
|
||||
* @param bool $debug
|
||||
*
|
||||
* @return ExceptionHandler The registered exception handler
|
||||
*/
|
||||
@@ -65,8 +61,8 @@ class ExceptionHandler
|
||||
*
|
||||
* @param \Exception $exception An \Exception instance
|
||||
*
|
||||
* @see sendPhpResponse
|
||||
* @see createResponse
|
||||
* @see sendPhpResponse()
|
||||
* @see createResponse()
|
||||
*/
|
||||
public function handle(\Exception $exception)
|
||||
{
|
||||
@@ -91,9 +87,12 @@ class ExceptionHandler
|
||||
$exception = FlattenException::create($exception);
|
||||
}
|
||||
|
||||
header(sprintf('HTTP/1.0 %s', $exception->getStatusCode()));
|
||||
foreach ($exception->getHeaders() as $name => $value) {
|
||||
header($name.': '.$value, false);
|
||||
if (!headers_sent()) {
|
||||
header(sprintf('HTTP/1.0 %s', $exception->getStatusCode()));
|
||||
foreach ($exception->getHeaders() as $name => $value) {
|
||||
header($name.': '.$value, false);
|
||||
}
|
||||
header('Content-Type: text/html; charset='.$this->charset);
|
||||
}
|
||||
|
||||
echo $this->decorate($this->getContent($exception), $this->getStylesheet($exception));
|
||||
@@ -112,7 +111,7 @@ class ExceptionHandler
|
||||
$exception = FlattenException::create($exception);
|
||||
}
|
||||
|
||||
return new Response($this->decorate($this->getContent($exception), $this->getStylesheet($exception)), $exception->getStatusCode(), $exception->getHeaders());
|
||||
return Response::create($this->decorate($this->getContent($exception), $this->getStylesheet($exception)), $exception->getStatusCode(), $exception->getHeaders())->setCharset($this->charset);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -133,6 +132,7 @@ class ExceptionHandler
|
||||
}
|
||||
|
||||
$content = '';
|
||||
$flags = PHP_VERSION_ID >= 50400 ? ENT_QUOTES | ENT_SUBSTITUTE : ENT_QUOTES;
|
||||
if ($this->debug) {
|
||||
try {
|
||||
$count = count($exception->getAllPrevious());
|
||||
@@ -140,7 +140,7 @@ class ExceptionHandler
|
||||
foreach ($exception->toArray() as $position => $e) {
|
||||
$ind = $count - $position + 1;
|
||||
$class = $this->abbrClass($e['class']);
|
||||
$message = nl2br($e['message']);
|
||||
$message = nl2br(htmlspecialchars($e['message'], $flags, $this->charset));
|
||||
$content .= sprintf(<<<EOF
|
||||
<div class="block_exception clear_fix">
|
||||
<h2><span>%d/%d</span> %s: %s</h2>
|
||||
@@ -157,10 +157,11 @@ EOF
|
||||
}
|
||||
if (isset($trace['file']) && isset($trace['line'])) {
|
||||
if ($linkFormat = ini_get('xdebug.file_link_format')) {
|
||||
$link = str_replace(array('%f', '%l'), array($trace['file'], $trace['line']), $linkFormat);
|
||||
$content .= sprintf(' in <a href="%s" title="Go to source">%s line %s</a>', $link, $trace['file'], $trace['line']);
|
||||
$link = strtr($linkFormat, array('%f' => $trace['file'], '%l' => $trace['line']));
|
||||
$link = htmlspecialchars($link, $flags, $this->charset);
|
||||
$content .= sprintf(' in <a href="%s" title="Go to source">%s line %d</a>', $link, htmlspecialchars($trace['file'], $flags, $this->charset), $trace['line']);
|
||||
} else {
|
||||
$content .= sprintf(' in %s line %s', $trace['file'], $trace['line']);
|
||||
$content .= sprintf(' in %s line %d', htmlspecialchars($trace['file'], $flags, $this->charset), $trace['line']);
|
||||
}
|
||||
}
|
||||
$content .= "</li>\n";
|
||||
@@ -171,7 +172,7 @@ EOF
|
||||
} catch (\Exception $e) {
|
||||
// something nasty happened and we cannot throw an exception anymore
|
||||
if ($this->debug) {
|
||||
$title = sprintf('Exception thrown when handling an exception (%s: %s)', get_class($exception), $exception->getMessage());
|
||||
$title = sprintf('Exception thrown when handling an exception (%s: %s)', get_class($e), htmlspecialchars($e->getMessage(), $flags, $this->charset));
|
||||
} else {
|
||||
$title = 'Whoops, looks like something went wrong.';
|
||||
}
|
||||
@@ -255,7 +256,7 @@ EOF;
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
|
||||
<meta charset="UTF-8" />
|
||||
<meta name="robots" content="noindex,nofollow" />
|
||||
<style>
|
||||
/* Copyright (c) 2010, Yahoo! Inc. All rights reserved. Code licensed under the BSD License: http://developer.yahoo.com/yui/license.html */
|
||||
@@ -278,7 +279,7 @@ EOF;
|
||||
{
|
||||
$parts = explode('\\', $class);
|
||||
|
||||
return sprintf("<abbr title=\"%s\">%s</abbr>", $class, array_pop($parts));
|
||||
return sprintf('<abbr title="%s">%s</abbr>', $class, array_pop($parts));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -290,14 +291,19 @@ EOF;
|
||||
*/
|
||||
private function formatArgs(array $args)
|
||||
{
|
||||
if (PHP_VERSION_ID >= 50400) {
|
||||
$flags = ENT_QUOTES | ENT_SUBSTITUTE;
|
||||
} else {
|
||||
$flags = ENT_QUOTES;
|
||||
}
|
||||
$result = array();
|
||||
foreach ($args as $key => $item) {
|
||||
if ('object' === $item[0]) {
|
||||
$formattedValue = sprintf("<em>object</em>(%s)", $this->abbrClass($item[1]));
|
||||
$formattedValue = sprintf('<em>object</em>(%s)', $this->abbrClass($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'", htmlspecialchars($item[1], ENT_QUOTES | ENT_SUBSTITUTE, $this->charset));
|
||||
$formattedValue = sprintf('<em>array</em>(%s)', is_array($item[1]) ? $this->formatArgs($item[1]) : $item[1]);
|
||||
} elseif ('string' === $item[0]) {
|
||||
$formattedValue = sprintf("'%s'", htmlspecialchars($item[1], $flags, $this->charset));
|
||||
} elseif ('null' === $item[0]) {
|
||||
$formattedValue = '<em>null</em>';
|
||||
} elseif ('boolean' === $item[0]) {
|
||||
@@ -305,7 +311,7 @@ EOF;
|
||||
} elseif ('resource' === $item[0]) {
|
||||
$formattedValue = '<em>resource</em>';
|
||||
} else {
|
||||
$formattedValue = str_replace("\n", '', var_export(htmlspecialchars((string) $item[1], ENT_QUOTES | ENT_SUBSTITUTE, $this->charset), true));
|
||||
$formattedValue = str_replace("\n", '', var_export(htmlspecialchars((string) $item[1], $flags, $this->charset), true));
|
||||
}
|
||||
|
||||
$result[] = is_int($key) ? $formattedValue : sprintf("'%s' => %s", $key, $formattedValue);
|
||||
|
||||
2
LICENSE
2
LICENSE
@@ -1,4 +1,4 @@
|
||||
Copyright (c) 2004-2013 Fabien Potencier
|
||||
Copyright (c) 2004-2015 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
|
||||
|
||||
28
README.md
28
README.md
@@ -6,23 +6,27 @@ Debug provides tools to make debugging easier.
|
||||
Enabling all debug tools is as easy as calling the `enable()` method on the
|
||||
main `Debug` class:
|
||||
|
||||
use Symfony\Component\Debug\Debug;
|
||||
```php
|
||||
use Symfony\Component\Debug\Debug;
|
||||
|
||||
Debug::enable();
|
||||
Debug::enable();
|
||||
```
|
||||
|
||||
You can also use the tools individually:
|
||||
|
||||
use Symfony\Component\Debug\ErrorHandler;
|
||||
use Symfony\Component\Debug\ExceptionHandler;
|
||||
```php
|
||||
use Symfony\Component\Debug\ErrorHandler;
|
||||
use Symfony\Component\Debug\ExceptionHandler;
|
||||
|
||||
error_reporting(-1);
|
||||
error_reporting(-1);
|
||||
|
||||
ErrorHandler::register($errorReportingLevel);
|
||||
if ('cli' !== php_sapi_name()) {
|
||||
ExceptionHandler::register();
|
||||
} elseif (!ini_get('log_errors') || ini_get('error_log')) {
|
||||
ini_set('display_errors', 1);
|
||||
}
|
||||
ErrorHandler::register($errorReportingLevel);
|
||||
if ('cli' !== php_sapi_name()) {
|
||||
ExceptionHandler::register();
|
||||
} elseif (!ini_get('log_errors') || ini_get('error_log')) {
|
||||
ini_set('display_errors', 1);
|
||||
}
|
||||
```
|
||||
|
||||
Note that the `Debug::enable()` call also registers the debug class loader
|
||||
from the Symfony ClassLoader component when available.
|
||||
@@ -36,5 +40,5 @@ Resources
|
||||
You can run the unit tests with the following command:
|
||||
|
||||
$ cd path/to/Symfony/Component/Debug/
|
||||
$ composer.phar install --dev
|
||||
$ composer install
|
||||
$ phpunit
|
||||
|
||||
@@ -12,14 +12,141 @@
|
||||
namespace Symfony\Component\Debug\Tests;
|
||||
|
||||
use Symfony\Component\Debug\ErrorHandler;
|
||||
use Symfony\Component\Debug\Exception\DummyException;
|
||||
|
||||
/**
|
||||
* ErrorHandlerTest
|
||||
* ErrorHandlerTest.
|
||||
*
|
||||
* @author Robert Schönthal <seroscho@googlemail.com>
|
||||
*/
|
||||
class ErrorHandlerTest extends \PHPUnit_Framework_TestCase
|
||||
{
|
||||
/**
|
||||
* @var int Error reporting level before running tests.
|
||||
*/
|
||||
protected $errorReporting;
|
||||
|
||||
protected function setUp()
|
||||
{
|
||||
$this->errorReporting = error_reporting(E_ALL | E_STRICT);
|
||||
$this->iniSet('display_errors', '1');
|
||||
}
|
||||
|
||||
protected function tearDown()
|
||||
{
|
||||
error_reporting($this->errorReporting);
|
||||
}
|
||||
|
||||
public function testCompileTimeError()
|
||||
{
|
||||
// the ContextErrorException must not be loaded to test the workaround
|
||||
// for https://bugs.php.net/bug.php?id=65322.
|
||||
if (class_exists('Symfony\Component\Debug\Exception\ContextErrorException', false)) {
|
||||
$this->markTestSkipped('The ContextErrorException class is already loaded.');
|
||||
}
|
||||
|
||||
$exceptionHandler = $this->getMock('Symfony\Component\Debug\ExceptionHandler', array('handle'));
|
||||
|
||||
// the following code forces some PHPUnit classes to be loaded
|
||||
// so that they will be available in the exception handler
|
||||
// as they won't be autoloaded by PHP
|
||||
class_exists('PHPUnit_Framework_MockObject_Invocation_Object');
|
||||
$this->assertInstanceOf('stdClass', new \stdClass());
|
||||
$this->assertEquals(1, 1);
|
||||
$this->assertStringStartsWith('foo', 'foobar');
|
||||
$this->assertArrayHasKey('bar', array('bar' => 'foo'));
|
||||
|
||||
$that = $this;
|
||||
$exceptionCheck = function ($exception) use ($that) {
|
||||
$that->assertInstanceOf('Symfony\Component\Debug\Exception\ContextErrorException', $exception);
|
||||
$that->assertEquals(2, $exception->getLine());
|
||||
if (PHP_VERSION_ID < 70000) {
|
||||
$that->assertEquals(E_STRICT, $exception->getSeverity());
|
||||
$that->assertStringStartsWith('Runtime Notice: Declaration of _CompileTimeError::foo() should be compatible with', $exception->getMessage());
|
||||
} else {
|
||||
$that->assertEquals(E_WARNING, $exception->getSeverity());
|
||||
$that->assertStringStartsWith('Warning: Declaration of _CompileTimeError::foo() should be compatible with', $exception->getMessage());
|
||||
}
|
||||
$that->assertArrayHasKey('bar', $exception->getContext());
|
||||
};
|
||||
|
||||
$exceptionHandler->expects($this->once())
|
||||
->method('handle')
|
||||
->will($this->returnCallback($exceptionCheck))
|
||||
;
|
||||
|
||||
ErrorHandler::register();
|
||||
set_exception_handler(array($exceptionHandler, 'handle'));
|
||||
|
||||
// dummy variable to check for in error handler.
|
||||
$bar = 123;
|
||||
|
||||
// trigger compile time error
|
||||
try {
|
||||
eval(<<<'PHP'
|
||||
class _BaseCompileTimeError { function foo() {} }
|
||||
class _CompileTimeError extends _BaseCompileTimeError { function foo($invalid) {} }
|
||||
PHP
|
||||
);
|
||||
} catch (DummyException $e) {
|
||||
// if an exception is thrown, the test passed
|
||||
}
|
||||
|
||||
restore_error_handler();
|
||||
restore_exception_handler();
|
||||
}
|
||||
|
||||
public function testNotice()
|
||||
{
|
||||
$exceptionHandler = $this->getMock('Symfony\Component\Debug\ExceptionHandler', array('handle'));
|
||||
set_exception_handler(array($exceptionHandler, 'handle'));
|
||||
|
||||
$that = $this;
|
||||
$exceptionCheck = function ($exception) use ($that) {
|
||||
$that->assertInstanceOf('Symfony\Component\Debug\Exception\ContextErrorException', $exception);
|
||||
$that->assertEquals(E_NOTICE, $exception->getSeverity());
|
||||
$that->assertEquals(__LINE__ + 40, $exception->getLine());
|
||||
$that->assertEquals(__FILE__, $exception->getFile());
|
||||
$that->assertRegexp('/^Notice: Undefined variable: (foo|bar)/', $exception->getMessage());
|
||||
$that->assertArrayHasKey('foobar', $exception->getContext());
|
||||
|
||||
$trace = $exception->getTrace();
|
||||
$that->assertEquals(__FILE__, $trace[0]['file']);
|
||||
$that->assertEquals('Symfony\Component\Debug\ErrorHandler', $trace[0]['class']);
|
||||
$that->assertEquals('handle', $trace[0]['function']);
|
||||
$that->assertEquals('->', $trace[0]['type']);
|
||||
|
||||
$that->assertEquals(__FILE__, $trace[1]['file']);
|
||||
$that->assertEquals(__CLASS__, $trace[1]['class']);
|
||||
$that->assertEquals('triggerNotice', $trace[1]['function']);
|
||||
$that->assertEquals('::', $trace[1]['type']);
|
||||
|
||||
$that->assertEquals(__CLASS__, $trace[2]['class']);
|
||||
$that->assertEquals('testNotice', $trace[2]['function']);
|
||||
$that->assertEquals('->', $trace[2]['type']);
|
||||
};
|
||||
|
||||
$exceptionHandler->expects($this->once())
|
||||
->method('handle')
|
||||
->will($this->returnCallback($exceptionCheck));
|
||||
ErrorHandler::register();
|
||||
|
||||
try {
|
||||
self::triggerNotice($this);
|
||||
} catch (DummyException $e) {
|
||||
// if an exception is thrown, the test passed
|
||||
}
|
||||
|
||||
restore_error_handler();
|
||||
}
|
||||
|
||||
// dummy function to test trace in error handler.
|
||||
private static function triggerNotice($that)
|
||||
{
|
||||
// dummy variable to check for in error handler.
|
||||
$foobar = 123;
|
||||
$that->assertSame('', $foo.$foo.$bar);
|
||||
}
|
||||
|
||||
public function testConstruct()
|
||||
{
|
||||
@@ -36,18 +163,18 @@ class ErrorHandlerTest extends \PHPUnit_Framework_TestCase
|
||||
public function testHandle()
|
||||
{
|
||||
$handler = ErrorHandler::register(0);
|
||||
$this->assertFalse($handler->handle(0, 'foo', 'foo.php', 12, 'foo'));
|
||||
$this->assertFalse($handler->handle(0, 'foo', 'foo.php', 12, array()));
|
||||
|
||||
restore_error_handler();
|
||||
|
||||
$handler = ErrorHandler::register(3);
|
||||
$this->assertFalse($handler->handle(4, 'foo', 'foo.php', 12, 'foo'));
|
||||
$this->assertFalse($handler->handle(4, 'foo', 'foo.php', 12, array()));
|
||||
|
||||
restore_error_handler();
|
||||
|
||||
$handler = ErrorHandler::register(3);
|
||||
try {
|
||||
$handler->handle(111, 'foo', 'foo.php', 12, 'foo');
|
||||
$handler->handle(111, 'foo', 'foo.php', 12, array());
|
||||
} catch (\ErrorException $e) {
|
||||
$this->assertSame('111: foo in foo.php line 12', $e->getMessage());
|
||||
$this->assertSame(111, $e->getSeverity());
|
||||
@@ -58,19 +185,19 @@ class ErrorHandlerTest extends \PHPUnit_Framework_TestCase
|
||||
restore_error_handler();
|
||||
|
||||
$handler = ErrorHandler::register(E_USER_DEPRECATED);
|
||||
$this->assertTrue($handler->handle(E_USER_DEPRECATED, 'foo', 'foo.php', 12, 'foo'));
|
||||
$this->assertTrue($handler->handle(E_USER_DEPRECATED, 'foo', 'foo.php', 12, array()));
|
||||
|
||||
restore_error_handler();
|
||||
|
||||
$handler = ErrorHandler::register(E_DEPRECATED);
|
||||
$this->assertTrue($handler->handle(E_DEPRECATED, 'foo', 'foo.php', 12, 'foo'));
|
||||
$this->assertTrue($handler->handle(E_DEPRECATED, 'foo', 'foo.php', 12, array()));
|
||||
|
||||
restore_error_handler();
|
||||
|
||||
$logger = $this->getMock('Psr\Log\LoggerInterface');
|
||||
|
||||
$that = $this;
|
||||
$warnArgCheck = function($message, $context) use ($that) {
|
||||
$warnArgCheck = function ($message, $context) use ($that) {
|
||||
$that->assertEquals('foo', $message);
|
||||
$that->assertArrayHasKey('type', $context);
|
||||
$that->assertEquals($context['type'], ErrorHandler::TYPE_DEPRECATION);
|
||||
@@ -86,7 +213,7 @@ class ErrorHandlerTest extends \PHPUnit_Framework_TestCase
|
||||
|
||||
$handler = ErrorHandler::register(E_USER_DEPRECATED);
|
||||
$handler->setLogger($logger);
|
||||
$handler->handle(E_USER_DEPRECATED, 'foo', 'foo.php', 12, 'foo');
|
||||
$handler->handle(E_USER_DEPRECATED, 'foo', 'foo.php', 12, array());
|
||||
|
||||
restore_error_handler();
|
||||
}
|
||||
|
||||
@@ -113,8 +113,7 @@ class FlattenExceptionTest extends \PHPUnit_Framework_TestCase
|
||||
|
||||
$this->assertEquals($exception->getMessage(), $flattened->getMessage(), 'The message is copied from the original exception.');
|
||||
$this->assertEquals($exception->getCode(), $flattened->getCode(), 'The code is copied from the original exception.');
|
||||
$this->assertEquals(get_class($exception), $flattened->getClass(), 'The class is set to the class of the original exception');
|
||||
|
||||
$this->assertInstanceOf($flattened->getClass(), $exception, 'The class is set to the class of the original exception');
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -127,9 +126,9 @@ class FlattenExceptionTest extends \PHPUnit_Framework_TestCase
|
||||
|
||||
$flattened->setPrevious($flattened2);
|
||||
|
||||
$this->assertSame($flattened2,$flattened->getPrevious());
|
||||
$this->assertSame($flattened2, $flattened->getPrevious());
|
||||
|
||||
$this->assertSame(array($flattened2),$flattened->getAllPrevious());
|
||||
$this->assertSame(array($flattened2), $flattened->getAllPrevious());
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -160,13 +159,13 @@ class FlattenExceptionTest extends \PHPUnit_Framework_TestCase
|
||||
|
||||
$this->assertEquals(array(
|
||||
array(
|
||||
'message'=> 'test',
|
||||
'class'=>'Exception',
|
||||
'trace'=>array(array(
|
||||
'namespace' => '', 'short_class' => '', 'class' => '','type' => '','function' => '', 'file' => 'foo.php', 'line' => 123,
|
||||
'args' => array()
|
||||
'message' => 'test',
|
||||
'class' => 'Exception',
|
||||
'trace' => array(array(
|
||||
'namespace' => '', 'short_class' => '', 'class' => '', 'type' => '', 'function' => '', 'file' => 'foo.php', 'line' => 123,
|
||||
'args' => array(),
|
||||
)),
|
||||
)
|
||||
),
|
||||
), $flattened->toArray());
|
||||
}
|
||||
|
||||
@@ -187,6 +186,28 @@ class FlattenExceptionTest extends \PHPUnit_Framework_TestCase
|
||||
$this->assertContains('*DEEP NESTED ARRAY*', serialize($trace));
|
||||
}
|
||||
|
||||
public function testTooBigArray()
|
||||
{
|
||||
$a = array();
|
||||
for ($i = 0; $i < 20; ++$i) {
|
||||
for ($j = 0; $j < 50; ++$j) {
|
||||
for ($k = 0; $k < 10; ++$k) {
|
||||
$a[$i][$j][$k] = 'value';
|
||||
}
|
||||
}
|
||||
}
|
||||
$a[20] = 'value';
|
||||
$a[21] = 'value1';
|
||||
$exception = $this->createException($a);
|
||||
|
||||
$flattened = FlattenException::create($exception);
|
||||
$trace = $flattened->getTrace();
|
||||
$serializeTrace = serialize($trace);
|
||||
|
||||
$this->assertContains('*SKIPPED over 10000 entries*', $serializeTrace);
|
||||
$this->assertNotContains('*value1*', $serializeTrace);
|
||||
}
|
||||
|
||||
private function createException($foo)
|
||||
{
|
||||
return new \Exception();
|
||||
@@ -202,7 +223,7 @@ class FlattenExceptionTest extends \PHPUnit_Framework_TestCase
|
||||
'line' => 123,
|
||||
'function' => 'test',
|
||||
'args' => array(
|
||||
unserialize('O:14:"BogusTestClass":0:{}')
|
||||
unserialize('O:14:"BogusTestClass":0:{}'),
|
||||
),
|
||||
),
|
||||
),
|
||||
@@ -211,25 +232,25 @@ class FlattenExceptionTest extends \PHPUnit_Framework_TestCase
|
||||
|
||||
$this->assertEquals(array(
|
||||
array(
|
||||
'message'=> 'test',
|
||||
'class'=>'Exception',
|
||||
'trace'=>array(
|
||||
'message' => 'test',
|
||||
'class' => 'Exception',
|
||||
'trace' => array(
|
||||
array(
|
||||
'namespace' => '', 'short_class' => '', 'class' => '','type' => '','function' => '',
|
||||
'file' => 'foo.php', 'line' => 123,
|
||||
'args' => 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(
|
||||
'namespace' => '', 'short_class' => '', 'class' => '', 'type' => '', 'function' => 'test',
|
||||
'file' => __FILE__, 'line' => 123,
|
||||
'args' => array(
|
||||
array(
|
||||
'incomplete-object', 'BogusTestClass'
|
||||
'incomplete-object', 'BogusTestClass',
|
||||
),
|
||||
),
|
||||
)
|
||||
),
|
||||
),
|
||||
)
|
||||
),
|
||||
), $flattened->toArray());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,13 +17,6 @@ use Symfony\Component\HttpKernel\Exception\MethodNotAllowedHttpException;
|
||||
|
||||
class ExceptionHandlerTest extends \PHPUnit_Framework_TestCase
|
||||
{
|
||||
protected function setUp()
|
||||
{
|
||||
if (!class_exists('Symfony\Component\HttpFoundation\Request')) {
|
||||
$this->markTestSkipped('The "HttpFoundation" component is not available');
|
||||
}
|
||||
}
|
||||
|
||||
public function testDebug()
|
||||
{
|
||||
$handler = new ExceptionHandler(false);
|
||||
@@ -64,6 +57,6 @@ class ExceptionHandlerTest extends \PHPUnit_Framework_TestCase
|
||||
public function testNestedExceptions()
|
||||
{
|
||||
$handler = new ExceptionHandler(true);
|
||||
$response = $handler->createResponse(new \RuntimeException('Foo', null, new \RuntimeException('Bar')));
|
||||
$response = $handler->createResponse(new \RuntimeException('Foo', 0, new \RuntimeException('Bar')));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
"type": "library",
|
||||
"description": "Symfony Debug Component",
|
||||
"keywords": [],
|
||||
"homepage": "http://symfony.com",
|
||||
"homepage": "https://symfony.com",
|
||||
"license": "MIT",
|
||||
"authors": [
|
||||
{
|
||||
@@ -12,14 +12,18 @@
|
||||
},
|
||||
{
|
||||
"name": "Symfony Community",
|
||||
"homepage": "http://symfony.com/contributors"
|
||||
"homepage": "https://symfony.com/contributors"
|
||||
}
|
||||
],
|
||||
"require": {
|
||||
"php": ">=5.3.3"
|
||||
},
|
||||
"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/http-kernel": "~2.1",
|
||||
"symfony/phpunit-bridge": "~2.7",
|
||||
"symfony/http-kernel": "~2.3.24|~2.5.9|~2.6,>=2.6.2",
|
||||
"symfony/http-foundation": "~2.1"
|
||||
},
|
||||
"suggest": {
|
||||
|
||||
@@ -1,16 +1,14 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
|
||||
<phpunit backupGlobals="false"
|
||||
backupStaticAttributes="false"
|
||||
<phpunit xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:noNamespaceSchemaLocation="http://schema.phpunit.de/4.1/phpunit.xsd"
|
||||
backupGlobals="false"
|
||||
colors="true"
|
||||
convertErrorsToExceptions="true"
|
||||
convertNoticesToExceptions="true"
|
||||
convertWarningsToExceptions="true"
|
||||
processIsolation="false"
|
||||
stopOnFailure="false"
|
||||
syntaxCheck="false"
|
||||
bootstrap="vendor/autoload.php"
|
||||
>
|
||||
<php>
|
||||
<ini name="error_reporting" value="-1" />
|
||||
</php>
|
||||
<testsuites>
|
||||
<testsuite name="Symfony Debug Component Test Suite">
|
||||
<directory>./Tests/</directory>
|
||||
|
||||
Reference in New Issue
Block a user