Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit cae0933

Browse files
committed
[Debug] Added an exception processor for dumping arguments
1 parent 4f299c7 commit cae0933

File tree

4 files changed

+191
-53
lines changed

4 files changed

+191
-53
lines changed

src/Symfony/Bundle/DebugBundle/Resources/config/services.xml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,10 @@
3939
<tag name="exception.processor" />
4040
</service>
4141

42+
<service id="debug.exception_processor.arguments" class="Symfony\Component\Debug\ArgumentsFlattenExceptionProcessor" public="false">
43+
<tag name="exception.processor" />
44+
<argument type="service" id="var_dumper.cloner" />
45+
</service>
4246
</services>
4347

4448
</container>
Lines changed: 167 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,167 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Symfony package.
5+
*
6+
* (c) Fabien Potencier <[email protected]>
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
namespace Symfony\Component\Debug;
13+
14+
use Symfony\Component\Debug\Exception\FlattenException;
15+
use Symfony\Component\VarDumper\Cloner\ClonerInterface;
16+
17+
/**
18+
* @author Martin Hasoň <[email protected]>
19+
*/
20+
class ArgumentsFlattenExceptionProcessor implements FlattenExceptionProcessorInterface
21+
{
22+
private $cloner;
23+
private $link;
24+
25+
public function __construct(ClonerInterface $cloner = null, $link = true)
26+
{
27+
$this->cloner = $cloner;
28+
$this->link = $link;
29+
}
30+
31+
/**
32+
* {@inheritdoc}
33+
*/
34+
public function process(\Exception $exception, FlattenException $flattenException, $master)
35+
{
36+
if (!$master) {
37+
return;
38+
}
39+
40+
$variables = array();
41+
$values = array();
42+
43+
$e = $exception;
44+
$f = $flattenException;
45+
46+
do {
47+
$trace = $f->getTrace();
48+
foreach ($e->getTrace() as $key => $entry) {
49+
if (!isset($entry['args']) || !isset($trace[$key])) {
50+
continue;
51+
}
52+
53+
$parameters = $this->getParameters($entry);
54+
55+
$arguments = array();
56+
foreach ($entry['args'] as $position => $argument) {
57+
$link = array_search($argument, $variables, true);
58+
59+
if (false === $link) {
60+
$link = hash('md5', uniqid(mt_rand(), true), false);
61+
$variables[$link] = $argument;
62+
$values[$link] = $this->link ? array('link', $link) : $this->flatten($argument);
63+
}
64+
65+
if (isset($parameters[$position])) {
66+
$arguments[$parameters[$position]->getName()] = $values[$link];
67+
} else {
68+
$arguments[] = $values[$link];
69+
}
70+
}
71+
72+
$trace[$key]['args'] = $arguments;
73+
}
74+
$f->replaceTrace($trace);
75+
} while (($e = $e->getPrevious()) && ($f = $f->getPrevious()));
76+
77+
if (!$this->link) {
78+
return;
79+
}
80+
81+
foreach (array_merge(array($flattenException), $flattenException->getAllPrevious()) as $f) {
82+
$f->setExtra('trace_arguments', $this->flatten($variables));
83+
}
84+
}
85+
86+
private function getParameters($entry)
87+
{
88+
if (!isset($entry['function'])) {
89+
return array();
90+
}
91+
92+
try {
93+
if (isset($entry['class'])) {
94+
$ref = new \ReflectionMethod($entry['class'], $entry['function']);
95+
} else {
96+
$ref = new \ReflectionFunction($entry['function']);
97+
}
98+
} catch (\ReflectionException $e) {
99+
return array();
100+
}
101+
102+
return $ref->getParameters();
103+
}
104+
105+
private function flatten($variable)
106+
{
107+
if (null === $this->cloner) {
108+
return $this->flattenValue($variable);
109+
} else {
110+
return $this->cloner->cloneVar($variable);
111+
}
112+
}
113+
114+
private function flattenValue($value, $level = 0, &$count = 0)
115+
{
116+
if ($count++ > 1e4) {
117+
return array('array', '*SKIPPED over 10000 entries*');
118+
}
119+
120+
if (is_object($value)) {
121+
return array('object', get_class($value));
122+
}
123+
124+
if (is_array($value)) {
125+
if ($level > 10) {
126+
return array('array', '*DEEP NESTED ARRAY*');
127+
}
128+
129+
$array = array();
130+
foreach ($value as $k => $v) {
131+
$array[$k] = $this->flattenValue($v, $level + 1, $count);
132+
}
133+
134+
return array('array', $array);
135+
}
136+
137+
if (null === $value) {
138+
return array('null', null);
139+
}
140+
141+
if (is_bool($value)) {
142+
return array('boolean', $value);
143+
}
144+
145+
if (is_float($value) || is_int($value)) {
146+
return array('number', $value);
147+
}
148+
149+
if (is_resource($value)) {
150+
return array('resource', get_resource_type($value));
151+
}
152+
153+
if ($value instanceof \__PHP_Incomplete_Class) {
154+
// Special case of object, is_object will return false
155+
return array('incomplete-object', $this->getClassNameFromIncomplete($value));
156+
}
157+
158+
return array('string', (string) $value);
159+
}
160+
161+
private function getClassNameFromIncomplete(\__PHP_Incomplete_Class $value)
162+
{
163+
$array = new \ArrayObject($value);
164+
165+
return $array['__PHP_Incomplete_Class_Name'];
166+
}
167+
}

src/Symfony/Component/Debug/Exception/FlattenException.php

Lines changed: 7 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@ public function __call($method, $args)
5151

5252
namespace Symfony\Component\Debug\Exception;
5353

54+
use Symfony\Component\Debug\ArgumentsFlattenExceptionProcessor;
5455
use Symfony\Component\HttpKernel\Exception\FlattenException as LegacyFlattenException;
5556
use Symfony\Component\HttpKernel\Exception\HttpExceptionInterface;
5657

@@ -95,10 +96,14 @@ public static function create(\Exception $exception, $statusCode = null, array $
9596
$e->setClass(get_class($exception));
9697
$e->setFile($exception->getFile());
9798
$e->setLine($exception->getLine());
99+
98100
if ($exception->getPrevious()) {
99-
$e->setPrevious(static::create($exception->getPrevious()));
101+
$e->setPrevious(static::create($exception->getPrevious(), -1));
100102
}
101103

104+
$processor = new ArgumentsFlattenExceptionProcessor(null, false);
105+
$processor->process($exception, $e, -1 !== $statusCode);
106+
102107
return $e;
103108
}
104109

@@ -249,7 +254,7 @@ public function setTrace($trace, $file, $line)
249254
'function' => isset($entry['function']) ? $entry['function'] : null,
250255
'file' => isset($entry['file']) ? $entry['file'] : null,
251256
'line' => isset($entry['line']) ? $entry['line'] : null,
252-
'args' => isset($entry['args']) ? $this->flattenArgs($entry['args']) : array(),
257+
'args' => array(),
253258
);
254259
}
255260
}
@@ -297,43 +302,4 @@ public function setExtra($name, $value)
297302
{
298303
$this->extras[$name] = $value;
299304
}
300-
301-
private function flattenArgs($args, $level = 0, &$count = 0)
302-
{
303-
$result = array();
304-
foreach ($args as $key => $value) {
305-
if (++$count > 1e4) {
306-
return array('array', '*SKIPPED over 10000 entries*');
307-
}
308-
if (is_object($value)) {
309-
$result[$key] = array('object', get_class($value));
310-
} elseif (is_array($value)) {
311-
if ($level > 10) {
312-
$result[$key] = array('array', '*DEEP NESTED ARRAY*');
313-
} else {
314-
$result[$key] = array('array', $this->flattenArgs($value, $level + 1, $count));
315-
}
316-
} elseif (null === $value) {
317-
$result[$key] = array('null', null);
318-
} elseif (is_bool($value)) {
319-
$result[$key] = array('boolean', $value);
320-
} elseif (is_resource($value)) {
321-
$result[$key] = array('resource', get_resource_type($value));
322-
} elseif ($value instanceof \__PHP_Incomplete_Class) {
323-
// Special case of object, is_object will return false
324-
$result[$key] = array('incomplete-object', $this->getClassNameFromIncomplete($value));
325-
} else {
326-
$result[$key] = array('string', (string) $value);
327-
}
328-
}
329-
330-
return $result;
331-
}
332-
333-
private function getClassNameFromIncomplete(\__PHP_Incomplete_Class $value)
334-
{
335-
$array = new \ArrayObject($value);
336-
337-
return $array['__PHP_Incomplete_Class_Name'];
338-
}
339305
}

src/Symfony/Component/Debug/Tests/Exception/FlattenExceptionTest.php

Lines changed: 13 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -215,20 +215,21 @@ private function createException($foo)
215215

216216
public function testSetTraceIncompleteClass()
217217
{
218-
$flattened = FlattenException::create(new \Exception('test', 123));
219-
$flattened->setTrace(
218+
$exception = new \Exception('test', 123);
219+
$traceReflection = new \ReflectionProperty($exception, 'trace');
220+
$traceReflection->setAccessible(true);
221+
$traceReflection->setValue($exception, array(
220222
array(
221-
array(
222-
'file' => __FILE__,
223-
'line' => 123,
224-
'function' => 'test',
225-
'args' => array(
226-
unserialize('O:14:"BogusTestClass":0:{}'),
227-
),
223+
'file' => __FILE__,
224+
'line' => 123,
225+
'function' => 'test',
226+
'args' => array(
227+
unserialize('O:14:"BogusTestClass":0:{}'),
228228
),
229229
),
230-
'foo.php', 123
231-
);
230+
));
231+
232+
$flattened = FlattenException::create($exception);
232233

233234
$this->assertEquals(array(
234235
array(
@@ -237,7 +238,7 @@ public function testSetTraceIncompleteClass()
237238
'trace' => array(
238239
-1 => array(
239240
'namespace' => '', 'short_class' => '', 'class' => '', 'type' => '', 'function' => '',
240-
'file' => 'foo.php', 'line' => 123,
241+
'file' => __FILE__, 'line' => 218,
241242
'args' => array(),
242243
),
243244
0 => array(

0 commit comments

Comments
 (0)