mirror of
https://github.com/symfony/debug.git
synced 2026-03-26 02:02:12 +01:00
* 2.8: [2.7] Fixed flatten exception recursion with errors Embedded identifier support Also transform inline mappings to objects Change the ExtensionInterface load method definition to bo identical to the documentation. add and correct armenian translations [Config] Fix array sort on normalization in edge case [Security] Run tests on all PHP versions [DomCrawler] Revert previous restriction, allow selection of every DOMNode object [Serializer] Make metadata interfaces internal [Yaml] fix indented line handling in folded blocks improve BrowserKit test coverage p1
257 lines
6.7 KiB
PHP
257 lines
6.7 KiB
PHP
<?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());
|
|
|
|
$previous = $exception->getPrevious();
|
|
|
|
if ($previous instanceof \Exception) {
|
|
$e->setPrevious(static::create($previous));
|
|
} elseif ($previous instanceof \Throwable) {
|
|
$e->setPrevious(static::create(new FatalThrowableError($previous)));
|
|
}
|
|
|
|
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)
|
|
{
|
|
$this->setTrace($exception->getTrace(), $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, &$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 + 1, $count));
|
|
}
|
|
} 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'];
|
|
}
|
|
}
|