merged branch fabpot/debug-component (PR #7441)

This PR was merged into the master branch.

Discussion
----------

[Debug] added the component (closes #6828, closes #6834, closes #7330)

| Q             | A
| ------------- | ---
| Bug fix?      | no
| New feature?  | yes
| BC breaks?    | no
| Deprecations? | yes
| Tests pass?   | yes
| Fixed tickets | #6828, #6834, #7330
| License       | MIT
| Doc PR        | symfony/symfony-docs#2479

You can use the individual tools, or register them all:

```php
use Symfony\Component\Debug\Debug;

Debug::enable();
```

Changes in Symfony SE: symfony/symfony-standard#523

Commits
-------

f693128 fixed typos
1ab1146 [Debug] fixed minor bugs
daa3a3c [Debug] changed composer to accept more versions
e455269 [Debug] ensured that the Debug tools can only be registered once
946bfb2 [Debug] made the exception handler independant of HttpFoundation
2b305c2 added a main Debug class to ease integration
2ff0927 [Debug] added the component (closes #6828, closes #6834, closes #7330)
This commit is contained in:
Fabien Potencier 2013-04-07 18:19:55 +02:00
commit 6d552c956e
21 changed files with 978 additions and 649 deletions

View File

@ -3,8 +3,8 @@ UPGRADE FROM 2.x to 3.0
### ClassLoader
* The `UniversalClassLoader` class has been removed in favor of `ClassLoader`. The only difference is that some method
names are different:
* The `UniversalClassLoader` class has been removed in favor of
`ClassLoader`. The only difference is that some method names are different:
* `registerNamespaces()` -> `addPrefixes()`
* `registerPrefixes()` -> `addPrefixes()`
@ -34,6 +34,16 @@ UPGRADE FROM 2.x to 3.0
* `Symfony\Bridge\Monolog\Logger`
* `Symfony\Component\HttpKernel\Log\NullLogger`
* The `Symfony\Component\HttpKernel\Kernel::init()` method has been removed.
* The following classes have been renamed as they have been moved to the
Debug component:
* `Symfony\Component\HttpKernel\Debug\ErrorHandler` -> `Symfony\Component\Debug\ErrorHandler`
* `Symfony\Component\HttpKernel\Debug\ExceptionHandler` -> `Symfony\Component\Debug\ExceptionHandler`
* `Symfony\Component\HttpKernel\Exception\FatalErrorException` -> `Symfony\Component\Debug\Exception\FatalErrorException`
* `Symfony\Component\HttpKernel\Exception\FlattenException` -> `Symfony\Component\Debug\Exception\FlattenException`
### Routing
* Some route settings have been renamed:

View File

@ -0,0 +1,3 @@
vendor/
composer.lock
phpunit.xml

View File

@ -0,0 +1,7 @@
CHANGELOG
=========
2.3.0
-----
* added the component

View File

@ -0,0 +1,56 @@
<?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;
use Symfony\Component\ClassLoader\DebugClassLoader;
/**
* Registers all the debug tools.
*
* @author Fabien Potencier <fabien@symfony.com>
*/
class Debug
{
private static $enabled = false;
/**
* Enables the debug tools.
*
* This method registers an error handler and an exception handler.
*
* If the Symfony ClassLoader component is available, a special
* class loader is also registered.
*
* @param integer $errorReportingLevel The level of error reporting you want
*/
public static function enable($errorReportingLevel = null)
{
if (static::$enabled) {
return;
}
static::$enabled = true;
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);
}
if (class_exists('Symfony\Component\ClassLoader\DebugClassLoader')) {
DebugClassLoader::enable();
}
}
}

View File

@ -0,0 +1,128 @@
<?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;
use Symfony\Component\Debug\Exception\FatalErrorException;
use Psr\Log\LoggerInterface;
/**
* ErrorHandler.
*
* @author Fabien Potencier <fabien@symfony.com>
*/
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_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',
);
private $level;
private $reservedMemory;
/** @var LoggerInterface */
private static $logger;
/**
* 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)
*
* @return The registered error handler
*/
public static function register($level = null)
{
$handler = new static();
$handler->setLevel($level);
ini_set('display_errors', 0);
set_error_handler(array($handler, 'handle'));
register_shutdown_function(array($handler, 'handleFatal'));
$handler->reservedMemory = str_repeat('x', 10240);
return $handler;
}
public function setLevel($level)
{
$this->level = null === $level ? error_reporting() : $level;
}
public static function setLogger(LoggerInterface $logger)
{
self::$logger = $logger;
}
/**
* @throws \ErrorException When error_reporting returns error
*/
public function handle($level, $message, $file, $line, $context)
{
if (0 === $this->level) {
return false;
}
if ($level & (E_USER_DEPRECATED | E_DEPRECATED)) {
if (null !== self::$logger) {
$stack = version_compare(PHP_VERSION, '5.4', '<') ? array_slice(debug_backtrace(false), 0, 10) : debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS, 10);
self::$logger->warning($message, array('type' => self::TYPE_DEPRECATION, 'stack' => $stack));
}
return true;
}
if (error_reporting() & $level && $this->level & $level) {
throw new \ErrorException(sprintf('%s: %s in %s line %d', isset($this->levels[$level]) ? $this->levels[$level] : $level, $message, $file, $line), 0, $level, $file, $line);
}
return false;
}
public function handleFatal()
{
if (null === $error = error_get_last()) {
return;
}
unset($this->reservedMemory);
$type = $error['type'];
if (0 === $this->level || !in_array($type, array(E_ERROR, E_CORE_ERROR, E_COMPILE_ERROR, E_PARSE))) {
return;
}
// get current exception handler
$exceptionHandler = set_exception_handler(function() {});
restore_exception_handler();
if (is_array($exceptionHandler) && $exceptionHandler[0] instanceof ExceptionHandler) {
$level = isset($this->levels[$type]) ? $this->levels[$type] : $type;
$message = sprintf('%s: %s in %s line %d', $level, $error['message'], $error['file'], $error['line']);
$exception = new FatalErrorException($message, 0, $type, $error['file'], $error['line']);
$exceptionHandler[0]->handle($exception);
}
}
}

View 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;
/**
* Fatal Error Exception.
*
* @author Konstanton Myakshin <koc-dp@yandex.ru>
*/
class FatalErrorException extends \ErrorException
{
}

View File

@ -0,0 +1,277 @@
<?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;
use Symfony\Component\HttpKernel\Exception\HttpExceptionInterface;
/**
* 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>
*/
class FlattenException
{
private $message;
private $code;
private $previous;
private $trace;
private $class;
private $statusCode;
private $headers;
private $file;
private $line;
public static function create(\Exception $exception, $statusCode = null, array $headers = array())
{
$e = new static();
$e->setMessage($exception->getMessage());
$e->setCode($exception->getCode());
if ($exception instanceof HttpExceptionInterface) {
$statusCode = $exception->getStatusCode();
$headers = array_merge($headers, $exception->getHeaders());
}
if (null === $statusCode) {
$statusCode = 500;
}
$e->setStatusCode($statusCode);
$e->setHeaders($headers);
$e->setTraceFromException($exception);
$e->setClass(get_class($exception));
$e->setFile($exception->getFile());
$e->setLine($exception->getLine());
if ($exception->getPrevious()) {
$e->setPrevious(static::create($exception->getPrevious()));
}
return $e;
}
public function toArray()
{
$exceptions = array();
foreach (array_merge(array($this), $this->getAllPrevious()) as $exception) {
$exceptions[] = array(
'message' => $exception->getMessage(),
'class' => $exception->getClass(),
'trace' => $exception->getTrace(),
);
}
return $exceptions;
}
public function getStatusCode()
{
return $this->statusCode;
}
public function setStatusCode($code)
{
$this->statusCode = $code;
}
public function getHeaders()
{
return $this->headers;
}
public function setHeaders(array $headers)
{
$this->headers = $headers;
}
public function getClass()
{
return $this->class;
}
public function setClass($class)
{
$this->class = $class;
}
public function getFile()
{
return $this->file;
}
public function setFile($file)
{
$this->file = $file;
}
public function getLine()
{
return $this->line;
}
public function setLine($line)
{
$this->line = $line;
}
public function getMessage()
{
return $this->message;
}
public function setMessage($message)
{
$this->message = $message;
}
public function getCode()
{
return $this->code;
}
public function setCode($code)
{
$this->code = $code;
}
public function getPrevious()
{
return $this->previous;
}
public function setPrevious(FlattenException $previous)
{
$this->previous = $previous;
}
public function getAllPrevious()
{
$exceptions = array();
$e = $this;
while ($e = $e->getPrevious()) {
$exceptions[] = $e;
}
return $exceptions;
}
public function getTrace()
{
return $this->trace;
}
public function setTraceFromException(\Exception $exception)
{
$trace = $exception->getTrace();
if ($exception instanceof FatalErrorException) {
if (function_exists('xdebug_get_function_stack')) {
$trace = array_slice(array_reverse(xdebug_get_function_stack()), 4);
foreach ($trace as $i => $frame) {
// XDebug pre 2.1.1 doesn't currently set the call type key http://bugs.xdebug.org/view.php?id=695
if (!isset($frame['type'])) {
$trace[$i]['type'] = '??';
}
if ('dynamic' === $trace[$i]['type']) {
$trace[$i]['type'] = '->';
} elseif ('static' === $trace[$i]['type']) {
$trace[$i]['type'] = '::';
}
// XDebug also has a different name for the parameters array
if (isset($frame['params']) && !isset($frame['args'])) {
$trace[$i]['args'] = $frame['params'];
unset($trace[$i]['params']);
}
}
} else {
$trace = array_slice(array_reverse($trace), 1);
}
}
$this->setTrace($trace, $exception->getFile(), $exception->getLine());
}
public function setTrace($trace, $file, $line)
{
$this->trace = array();
$this->trace[] = array(
'namespace' => '',
'short_class' => '',
'class' => '',
'type' => '',
'function' => '',
'file' => $file,
'line' => $line,
'args' => array(),
);
foreach ($trace as $entry) {
$class = '';
$namespace = '';
if (isset($entry['class'])) {
$parts = explode('\\', $entry['class']);
$class = array_pop($parts);
$namespace = implode('\\', $parts);
}
$this->trace[] = array(
'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(),
);
}
}
private function flattenArgs($args, $level = 0)
{
$result = array();
foreach ($args as $key => $value) {
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));
}
} elseif (null === $value) {
$result[$key] = array('null', null);
} elseif (is_bool($value)) {
$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);
}
}
return $result;
}
private function getClassNameFromIncomplete(\__PHP_Incomplete_Class $value)
{
$array = new \ArrayObject($value);
return $array['__PHP_Incomplete_Class_Name'];
}
}

View File

@ -0,0 +1,316 @@
<?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;
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.
*
* It is mostly useful in debug mode to replace the default PHP/XDebug
* output with something prettier and more useful.
*
* As this class is mainly used during Kernel boot, where nothing is yet
* available, the Response content is always HTML.
*
* @author Fabien Potencier <fabien@symfony.com>
*/
class ExceptionHandler
{
private $debug;
private $charset;
public function __construct($debug = true, $charset = 'UTF-8')
{
$this->debug = $debug;
$this->charset = $charset;
}
/**
* Registers the exception handler.
*
* @param Boolean $debug
*
* @return ExceptionHandler The registered exception handler
*/
public static function register($debug = true)
{
$handler = new static($debug);
set_exception_handler(array($handler, 'handle'));
return $handler;
}
/**
* 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
*
* @see sendPhpResponse
* @see createResponse
*/
public function handle(\Exception $exception)
{
if (class_exists('Symfony\Component\HttpFoundation\Response')) {
$this->createResponse($exception)->send();
} else {
$this->sendPhpResponse($exception);
}
}
/**
* Sends the error associated with the given Exception as a plain PHP response.
*
* This method uses plain PHP functions like header() and echo to output
* the response.
*
* @param \Exception|FlattenException $exception An \Exception instance
*/
public function sendPhpResponse($exception)
{
if (!$exception instanceof FlattenException) {
$exception = FlattenException::create($exception);
}
header(sprintf('HTTP/1.0 %s', $exception->getStatusCode()));
foreach ($exception->getHeaders() as $name => $value) {
header($name.': '.$value, false);
}
echo $this->decorate($this->getContent($exception), $this->getStylesheet($exception));
}
/**
* Creates the error Response associated with the given Exception.
*
* @param \Exception|FlattenException $exception An \Exception instance
*
* @return Response A Response instance
*/
public function createResponse($exception)
{
if (!$exception instanceof FlattenException) {
$exception = FlattenException::create($exception);
}
return new Response($this->decorate($this->getContent($exception), $this->getStylesheet($exception)), $exception->getStatusCode(), $exception->getHeaders());
}
/**
* Gets the HTML content associated with the given exception.
*
* @param FlattenException $exception A FlattenException instance
*
* @return string The content as a string
*/
public function getContent(FlattenException $exception)
{
switch ($exception->getStatusCode()) {
case 404:
$title = 'Sorry, the page you are looking for could not be found.';
break;
default:
$title = 'Whoops, looks like something went wrong.';
}
$content = '';
if ($this->debug) {
try {
$count = count($exception->getAllPrevious());
$total = $count + 1;
foreach ($exception->toArray() as $position => $e) {
$ind = $count - $position + 1;
$class = $this->abbrClass($e['class']);
$message = nl2br($e['message']);
$content .= sprintf(<<<EOF
<div class="block_exception clear_fix">
<h2><span>%d/%d</span> %s: %s</h2>
</div>
<div class="block">
<ol class="traces list_exception">
EOF
, $ind, $total, $class, $message);
foreach ($e['trace'] as $trace) {
$content .= ' <li>';
if ($trace['function']) {
$content .= sprintf('at %s%s%s(%s)', $this->abbrClass($trace['class']), $trace['type'], $trace['function'], $this->formatArgs($trace['args']));
}
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']);
} else {
$content .= sprintf(' in %s line %s', $trace['file'], $trace['line']);
}
}
$content .= "</li>\n";
}
$content .= " </ol>\n</div>\n";
}
} 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());
} else {
$title = 'Whoops, looks like something went wrong.';
}
}
}
return <<<EOF
<div id="sf-resetcontent" class="sf-reset">
<h1>$title</h1>
$content
</div>
EOF;
}
/**
* Gets the stylesheet associated with the given exception.
*
* @param FlattenException $exception A FlattenException instance
*
* @return string The stylesheet as a string
*/
public function getStylesheet(FlattenException $exception)
{
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; }
.sf-reset .clear_fix { display:inline-block; }
.sf-reset * html .clear_fix { height:1%; }
.sf-reset .clear_fix { display:block; }
.sf-reset, .sf-reset .block { margin: auto }
.sf-reset abbr { border-bottom: 1px dotted #000; cursor: help; }
.sf-reset p { font-size:14px; line-height:20px; color:#868686; padding-bottom:20px }
.sf-reset strong { font-weight:bold; }
.sf-reset a { color:#6c6159; }
.sf-reset a img { border:none; }
.sf-reset a:hover { text-decoration:underline; }
.sf-reset em { font-style:italic; }
.sf-reset h1, .sf-reset h2 { font: 20px Georgia, "Times New Roman", Times, serif }
.sf-reset h2 span { background-color: #fff; color: #333; padding: 6px; float: left; margin-right: 10px; }
.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;
border-right:1px solid #ccc;
border-left:1px solid #ccc;
}
.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;
border-right:1px solid #ccc;
border-left:1px solid #ccc;
overflow: hidden;
word-wrap: break-word;
}
.sf-reset li a { background:none; color:#868686; text-decoration:none; }
.sf-reset li 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;
}
EOF;
}
private function decorate($content, $css)
{
return <<<EOF
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; 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 */
html{color:#000;background:#FFF;}body,div,dl,dt,dd,ul,ol,li,h1,h2,h3,h4,h5,h6,pre,code,form,fieldset,legend,input,textarea,p,blockquote,th,td{margin:0;padding:0;}table{border-collapse:collapse;border-spacing:0;}fieldset,img{border:0;}address,caption,cite,code,dfn,em,strong,th,var{font-style:normal;font-weight:normal;}li{list-style:none;}caption,th{text-align:left;}h1,h2,h3,h4,h5,h6{font-size:100%;font-weight:normal;}q:before,q:after{content:'';}abbr,acronym{border:0;font-variant:normal;}sup{vertical-align:text-top;}sub{vertical-align:text-bottom;}input,textarea,select{font-family:inherit;font-size:inherit;font-weight:inherit;}input,textarea,select{*font-size:100%;}legend{color:#000;}
html { background: #eee; padding: 10px }
img { border: 0; }
#sf-resetcontent { width:970px; margin:0 auto; }
$css
</style>
</head>
<body>
$content
</body>
</html>
EOF;
}
private function abbrClass($class)
{
$parts = explode('\\', $class);
return sprintf("<abbr title=\"%s\">%s</abbr>", $class, array_pop($parts));
}
/**
* Formats an array as a string.
*
* @param array $args The argument array
*
* @return string
*/
private function formatArgs(array $args)
{
$result = array();
foreach ($args as $key => $item) {
if ('object' === $item[0]) {
$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));
} elseif ('null' === $item[0]) {
$formattedValue = '<em>null</em>';
} elseif ('boolean' === $item[0]) {
$formattedValue = '<em>'.strtolower(var_export($item[1], true)).'</em>';
} 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));
}
$result[] = is_int($key) ? $formattedValue : sprintf("'%s' => %s", $key, $formattedValue);
}
return implode(', ', $result);
}
}

View File

@ -0,0 +1,19 @@
Copyright (c) 2004-2013 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
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is furnished
to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.

View File

@ -0,0 +1,40 @@
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:
use Symfony\Component\Debug\Debug;
Debug::enable();
You can also use the tools individually:
use Symfony\Component\Debug\ErrorHandler;
use Symfony\Component\Debug\ExceptionHandler;
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);
}
Note that the `Debug::enable()` call also registers the debug class loader
from the Symfony ClassLoader component when available.
This component can optionally take advantage of the features of the HttpKernel
and HttpFoundation components.
Resources
---------
You can run the unit tests with the following command:
$ cd path/to/Symfony/Component/Debug/
$ composer.phar install --dev
$ phpunit

View File

@ -9,9 +9,9 @@
* file that was distributed with this source code.
*/
namespace Symfony\Component\HttpKernel\Tests\Debug;
namespace Symfony\Component\Debug\Tests;
use Symfony\Component\HttpKernel\Debug\ErrorHandler;
use Symfony\Component\Debug\ErrorHandler;
/**
* ErrorHandlerTest

View File

@ -9,9 +9,9 @@
* file that was distributed with this source code.
*/
namespace Symfony\Component\HttpKernel\Tests\Exception;
namespace Symfony\Component\Debug\Tests\Exception;
use Symfony\Component\HttpKernel\Exception\FlattenException;
use Symfony\Component\Debug\Exception\FlattenException;
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
use Symfony\Component\HttpKernel\Exception\MethodNotAllowedHttpException;
use Symfony\Component\HttpKernel\Exception\UnauthorizedHttpException;

View File

@ -9,9 +9,9 @@
* file that was distributed with this source code.
*/
namespace Symfony\Component\HttpKernel\Tests\Debug;
namespace Symfony\Component\Debug\Tests;
use Symfony\Component\HttpKernel\Debug\ExceptionHandler;
use Symfony\Component\Debug\ExceptionHandler;
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
use Symfony\Component\HttpKernel\Exception\MethodNotAllowedHttpException;

View File

@ -0,0 +1,40 @@
{
"name": "symfony/debug",
"type": "library",
"description": "Symfony Debug Component",
"keywords": [],
"homepage": "http://symfony.com",
"license": "MIT",
"authors": [
{
"name": "Fabien Potencier",
"email": "fabien@symfony.com"
},
{
"name": "Symfony Community",
"homepage": "http://symfony.com/contributors"
}
],
"require": {
"php": ">=5.3.3"
},
"require-dev": {
"symfony/http-kernel": "~2.1",
"symfony/http-foundation": "~2.1"
},
"suggest": {
"symfony/http-foundation": "~2.1",
"symfony/http-kernel": "~2.1",
"symfony/class-loader": "~2.1"
},
"autoload": {
"psr-0": { "Symfony\\Component\\Debug\\": "" }
},
"target-dir": "Symfony/Component/Debug",
"minimum-stability": "dev",
"extra": {
"branch-alias": {
"dev-master": "2.3-dev"
}
}
}

View File

@ -0,0 +1,29 @@
<?xml version="1.0" encoding="UTF-8"?>
<phpunit backupGlobals="false"
backupStaticAttributes="false"
colors="true"
convertErrorsToExceptions="true"
convertNoticesToExceptions="true"
convertWarningsToExceptions="true"
processIsolation="false"
stopOnFailure="false"
syntaxCheck="false"
bootstrap="vendor/autoload.php"
>
<testsuites>
<testsuite name="Symfony Debug Component Test Suite">
<directory>./Tests/</directory>
</testsuite>
</testsuites>
<filter>
<whitelist>
<directory>./</directory>
<exclude>
<directory>./Tests</directory>
<directory>./vendor</directory>
</exclude>
</whitelist>
</filter>
</phpunit>

View File

@ -4,6 +4,9 @@ CHANGELOG
2.3.0
-----
* deprecated `Symfony\Component\HttpKernel\Debug\ErrorHandler`, `Symfony\Component\HttpKernel\Debug\ExceptionHandler`,
`Symfony\Component\HttpKernel\Exception\FatalErrorException`, and `Symfony\Component\HttpKernel\Exception\FlattenException`
* deprecated `Symfony\Component\HttpKernel\Kernel::init()``
* added the possibility to specify an id an extra attributes to hinclude tags
* added the collect of data if a controller is a Closure in the Request collector

View File

@ -11,118 +11,15 @@
namespace Symfony\Component\HttpKernel\Debug;
use Symfony\Component\HttpKernel\Exception\FatalErrorException;
use Psr\Log\LoggerInterface;
use Symfony\Component\Debug\ErrorHandler as DebugErrorHandler;
/**
* ErrorHandler.
*
* @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 ErrorHandler
class ErrorHandler extends DebugErrorHandler
{
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_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',
);
private $level;
private $reservedMemory;
/** @var LoggerInterface */
private static $logger;
/**
* Register 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)
*
* @return The registered error handler
*/
public static function register($level = null)
{
$handler = new static();
$handler->setLevel($level);
ini_set('display_errors', 0);
set_error_handler(array($handler, 'handle'));
register_shutdown_function(array($handler, 'handleFatal'));
$handler->reservedMemory = str_repeat('x', 10240);
return $handler;
}
public function setLevel($level)
{
$this->level = null === $level ? error_reporting() : $level;
}
public static function setLogger(LoggerInterface $logger)
{
self::$logger = $logger;
}
/**
* @throws \ErrorException When error_reporting returns error
*/
public function handle($level, $message, $file, $line, $context)
{
if (0 === $this->level) {
return false;
}
if ($level & (E_USER_DEPRECATED | E_DEPRECATED)) {
if (null !== self::$logger) {
$stack = version_compare(PHP_VERSION, '5.4', '<') ? array_slice(debug_backtrace(false), 0, 10) : debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS, 10);
self::$logger->warning($message, array('type' => self::TYPE_DEPRECATION, 'stack' => $stack));
}
return true;
}
if (error_reporting() & $level && $this->level & $level) {
throw new \ErrorException(sprintf('%s: %s in %s line %d', isset($this->levels[$level]) ? $this->levels[$level] : $level, $message, $file, $line), 0, $level, $file, $line);
}
return false;
}
public function handleFatal()
{
if (null === $error = error_get_last()) {
return;
}
unset($this->reservedMemory);
$type = $error['type'];
if (0 === $this->level || !in_array($type, array(E_ERROR, E_CORE_ERROR, E_COMPILE_ERROR, E_PARSE))) {
return;
}
// get current exception handler
$exceptionHandler = set_exception_handler(function() {});
restore_exception_handler();
if (is_array($exceptionHandler) && $exceptionHandler[0] instanceof ExceptionHandler) {
$level = isset($this->levels[$type]) ? $this->levels[$type] : $type;
$message = sprintf('%s: %s in %s line %d', $level, $error['message'], $error['file'], $error['line']);
$exception = new FatalErrorException($message, 0, $type, $error['file'], $error['line']);
$exceptionHandler[0]->handle($exception);
}
}
}

View File

@ -11,273 +11,15 @@
namespace Symfony\Component\HttpKernel\Debug;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpKernel\Exception\FlattenException;
if (!defined('ENT_SUBSTITUTE')) {
define('ENT_SUBSTITUTE', 8);
}
use Symfony\Component\Debug\ExceptionHandler as DebugExceptionHandler;
/**
* ExceptionHandler converts an exception to a Response object.
*
* It is mostly useful in debug mode to replace the default PHP/XDebug
* output with something prettier and more useful.
*
* As this class is mainly used during Kernel boot, where nothing is yet
* available, the Response content is always HTML.
*
* @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 ExceptionHandler
class ExceptionHandler extends DebugExceptionHandler
{
private $debug;
private $charset;
public function __construct($debug = true, $charset = 'UTF-8')
{
$this->debug = $debug;
$this->charset = $charset;
}
/**
* Register the exception handler.
*
* @param Boolean $debug
*
* @return ExceptionHandler The registered exception handler
*/
public static function register($debug = true)
{
$handler = new static($debug);
set_exception_handler(array($handler, 'handle'));
return $handler;
}
/**
* Sends a Response for the given Exception.
*
* @param \Exception $exception An \Exception instance
*/
public function handle(\Exception $exception)
{
$this->createResponse($exception)->send();
}
/**
* Creates the error Response associated with the given Exception.
*
* @param \Exception|FlattenException $exception An \Exception instance
*
* @return Response A Response instance
*/
public function createResponse($exception)
{
if (!$exception instanceof FlattenException) {
$exception = FlattenException::create($exception);
}
return new Response($this->decorate($this->getContent($exception), $this->getStylesheet($exception)), $exception->getStatusCode(), $exception->getHeaders());
}
/**
* Gets the HTML content associated with the given exception.
*
* @param FlattenException $exception A FlattenException instance
*
* @return string The content as a string
*/
public function getContent(FlattenException $exception)
{
switch ($exception->getStatusCode()) {
case 404:
$title = 'Sorry, the page you are looking for could not be found.';
break;
default:
$title = 'Whoops, looks like something went wrong.';
}
$content = '';
if ($this->debug) {
try {
$count = count($exception->getAllPrevious());
$total = $count + 1;
foreach ($exception->toArray() as $position => $e) {
$ind = $count - $position + 1;
$class = $this->abbrClass($e['class']);
$message = nl2br($e['message']);
$content .= sprintf(<<<EOF
<div class="block_exception clear_fix">
<h2><span>%d/%d</span> %s: %s</h2>
</div>
<div class="block">
<ol class="traces list_exception">
EOF
, $ind, $total, $class, $message);
foreach ($e['trace'] as $trace) {
$content .= ' <li>';
if ($trace['function']) {
$content .= sprintf('at %s%s%s(%s)', $this->abbrClass($trace['class']), $trace['type'], $trace['function'], $this->formatArgs($trace['args']));
}
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']);
} else {
$content .= sprintf(' in %s line %s', $trace['file'], $trace['line']);
}
}
$content .= "</li>\n";
}
$content .= " </ol>\n</div>\n";
}
} 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());
} else {
$title = 'Whoops, looks like something went wrong.';
}
}
}
return <<<EOF
<div id="sf-resetcontent" class="sf-reset">
<h1>$title</h1>
$content
</div>
EOF;
}
/**
* Gets the stylesheet associated with the given exception.
*
* @param FlattenException $exception A FlattenException instance
*
* @return string The stylesheet as a string
*/
public function getStylesheet(FlattenException $exception)
{
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; }
.sf-reset .clear_fix { display:inline-block; }
.sf-reset * html .clear_fix { height:1%; }
.sf-reset .clear_fix { display:block; }
.sf-reset, .sf-reset .block { margin: auto }
.sf-reset abbr { border-bottom: 1px dotted #000; cursor: help; }
.sf-reset p { font-size:14px; line-height:20px; color:#868686; padding-bottom:20px }
.sf-reset strong { font-weight:bold; }
.sf-reset a { color:#6c6159; }
.sf-reset a img { border:none; }
.sf-reset a:hover { text-decoration:underline; }
.sf-reset em { font-style:italic; }
.sf-reset h1, .sf-reset h2 { font: 20px Georgia, "Times New Roman", Times, serif }
.sf-reset h2 span { background-color: #fff; color: #333; padding: 6px; float: left; margin-right: 10px; }
.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;
border-right:1px solid #ccc;
border-left:1px solid #ccc;
}
.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;
border-right:1px solid #ccc;
border-left:1px solid #ccc;
overflow: hidden;
word-wrap: break-word;
}
.sf-reset li a { background:none; color:#868686; text-decoration:none; }
.sf-reset li 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;
}
EOF;
}
private function decorate($content, $css)
{
return <<<EOF
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; 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 */
html{color:#000;background:#FFF;}body,div,dl,dt,dd,ul,ol,li,h1,h2,h3,h4,h5,h6,pre,code,form,fieldset,legend,input,textarea,p,blockquote,th,td{margin:0;padding:0;}table{border-collapse:collapse;border-spacing:0;}fieldset,img{border:0;}address,caption,cite,code,dfn,em,strong,th,var{font-style:normal;font-weight:normal;}li{list-style:none;}caption,th{text-align:left;}h1,h2,h3,h4,h5,h6{font-size:100%;font-weight:normal;}q:before,q:after{content:'';}abbr,acronym{border:0;font-variant:normal;}sup{vertical-align:text-top;}sub{vertical-align:text-bottom;}input,textarea,select{font-family:inherit;font-size:inherit;font-weight:inherit;}input,textarea,select{*font-size:100%;}legend{color:#000;}
html { background: #eee; padding: 10px }
img { border: 0; }
#sf-resetcontent { width:970px; margin:0 auto; }
$css
</style>
</head>
<body>
$content
</body>
</html>
EOF;
}
private function abbrClass($class)
{
$parts = explode('\\', $class);
return sprintf("<abbr title=\"%s\">%s</abbr>", $class, array_pop($parts));
}
/**
* Formats an array as a string.
*
* @param array $args The argument array
*
* @return string
*/
private function formatArgs(array $args)
{
$result = array();
foreach ($args as $key => $item) {
if ('object' === $item[0]) {
$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));
} elseif ('null' === $item[0]) {
$formattedValue = '<em>null</em>';
} elseif ('boolean' === $item[0]) {
$formattedValue = '<em>'.strtolower(var_export($item[1], true)).'</em>';
} 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));
}
$result[] = is_int($key) ? $formattedValue : sprintf("'%s' => %s", $key, $formattedValue);
}
return implode(', ', $result);
}
}

View File

@ -11,12 +11,15 @@
namespace Symfony\Component\HttpKernel\Exception;
use Symfony\Component\Debug\Exception\FatalErrorException as DebugFatalErrorException;
/**
* 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
class FatalErrorException extends DebugFatalErrorException
{
}

View File

@ -11,265 +11,17 @@
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
class FlattenException extends DebugFlattenException
{
private $message;
private $code;
private $previous;
private $trace;
private $class;
private $statusCode;
private $headers;
private $file;
private $line;
public static function create(\Exception $exception, $statusCode = null, array $headers = array())
{
$e = new static();
$e->setMessage($exception->getMessage());
$e->setCode($exception->getCode());
if ($exception instanceof HttpExceptionInterface) {
$statusCode = $exception->getStatusCode();
$headers = array_merge($headers, $exception->getHeaders());
}
if (null === $statusCode) {
$statusCode = 500;
}
$e->setStatusCode($statusCode);
$e->setHeaders($headers);
$e->setTraceFromException($exception);
$e->setClass(get_class($exception));
$e->setFile($exception->getFile());
$e->setLine($exception->getLine());
if ($exception->getPrevious()) {
$e->setPrevious(static::create($exception->getPrevious()));
}
return $e;
}
public function toArray()
{
$exceptions = array();
foreach (array_merge(array($this), $this->getAllPrevious()) as $exception) {
$exceptions[] = array(
'message' => $exception->getMessage(),
'class' => $exception->getClass(),
'trace' => $exception->getTrace(),
);
}
return $exceptions;
}
public function getStatusCode()
{
return $this->statusCode;
}
public function setStatusCode($code)
{
$this->statusCode = $code;
}
public function getHeaders()
{
return $this->headers;
}
public function setHeaders(array $headers)
{
$this->headers = $headers;
}
public function getClass()
{
return $this->class;
}
public function setClass($class)
{
$this->class = $class;
}
public function getFile()
{
return $this->file;
}
public function setFile($file)
{
$this->file = $file;
}
public function getLine()
{
return $this->line;
}
public function setLine($line)
{
$this->line = $line;
}
public function getMessage()
{
return $this->message;
}
public function setMessage($message)
{
$this->message = $message;
}
public function getCode()
{
return $this->code;
}
public function setCode($code)
{
$this->code = $code;
}
public function getPrevious()
{
return $this->previous;
}
public function setPrevious(FlattenException $previous)
{
$this->previous = $previous;
}
public function getAllPrevious()
{
$exceptions = array();
$e = $this;
while ($e = $e->getPrevious()) {
$exceptions[] = $e;
}
return $exceptions;
}
public function getTrace()
{
return $this->trace;
}
public function setTraceFromException(\Exception $exception)
{
$trace = $exception->getTrace();
if ($exception instanceof FatalErrorException) {
if (function_exists('xdebug_get_function_stack')) {
$trace = array_slice(array_reverse(xdebug_get_function_stack()), 4);
foreach ($trace as $i => $frame) {
// XDebug pre 2.1.1 doesn't currently set the call type key http://bugs.xdebug.org/view.php?id=695
if (!isset($frame['type'])) {
$trace[$i]['type'] = '??';
}
if ('dynamic' === $trace[$i]['type']) {
$trace[$i]['type'] = '->';
} elseif ('static' === $trace[$i]['type']) {
$trace[$i]['type'] = '::';
}
// XDebug also has a different name for the parameters array
if (isset($frame['params']) && !isset($frame['args'])) {
$trace[$i]['args'] = $frame['params'];
unset($trace[$i]['params']);
}
}
} else {
$trace = array_slice(array_reverse($trace), 1);
}
}
$this->setTrace($trace, $exception->getFile(), $exception->getLine());
}
public function setTrace($trace, $file, $line)
{
$this->trace = array();
$this->trace[] = array(
'namespace' => '',
'short_class' => '',
'class' => '',
'type' => '',
'function' => '',
'file' => $file,
'line' => $line,
'args' => array(),
);
foreach ($trace as $entry) {
$class = '';
$namespace = '';
if (isset($entry['class'])) {
$parts = explode('\\', $entry['class']);
$class = array_pop($parts);
$namespace = implode('\\', $parts);
}
$this->trace[] = array(
'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(),
);
}
}
private function flattenArgs($args, $level = 0)
{
$result = array();
foreach ($args as $key => $value) {
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));
}
} elseif (null === $value) {
$result[$key] = array('null', null);
} elseif (is_bool($value)) {
$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);
}
}
return $result;
}
private function getClassNameFromIncomplete(\__PHP_Incomplete_Class $value)
{
$array = new \ArrayObject($value);
return $array['__PHP_Incomplete_Class_Name'];
}
}

View File

@ -27,13 +27,10 @@ use Symfony\Component\HttpKernel\Bundle\BundleInterface;
use Symfony\Component\HttpKernel\Config\FileLocator;
use Symfony\Component\HttpKernel\DependencyInjection\MergeExtensionConfigurationPass;
use Symfony\Component\HttpKernel\DependencyInjection\AddClassesToCachePass;
use Symfony\Component\HttpKernel\Debug\ErrorHandler;
use Symfony\Component\HttpKernel\Debug\ExceptionHandler;
use Symfony\Component\Config\Loader\LoaderResolver;
use Symfony\Component\Config\Loader\DelegatingLoader;
use Symfony\Component\Config\ConfigCache;
use Symfony\Component\ClassLoader\ClassCollectionLoader;
use Symfony\Component\ClassLoader\DebugClassLoader;
/**
* The Kernel is the heart of the Symfony system.
@ -60,7 +57,6 @@ abstract class Kernel implements KernelInterface, TerminableInterface
protected $name;
protected $startTime;
protected $classes;
protected $errorReportingLevel;
const VERSION = '2.3.0-DEV';
const VERSION_ID = '20300';
@ -94,21 +90,11 @@ abstract class Kernel implements KernelInterface, TerminableInterface
$this->init();
}
/**
* @deprecated Deprecated since version 2.3, to be removed in 3.0. Move your logic in the constructor instead.
*/
public function init()
{
ini_set('display_errors', 0);
if ($this->debug) {
error_reporting(-1);
DebugClassLoader::enable();
ErrorHandler::register($this->errorReportingLevel);
if ('cli' !== php_sapi_name()) {
ExceptionHandler::register();
} elseif (!ini_get('log_errors') || ini_get('error_log')) {
ini_set('display_errors', 1);
}
}
}
public function __clone()