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

Skip to content

Commit b5fbe18

Browse files
[ErrorHandler] Rewrite logic to dump exception properties and fix serializing FlattenException
1 parent 1f43acb commit b5fbe18

File tree

9 files changed

+58
-35
lines changed

9 files changed

+58
-35
lines changed

src/Symfony/Component/ErrorHandler/ErrorRenderer/HtmlErrorRenderer.php

Lines changed: 4 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@
1717
use Symfony\Component\HttpFoundation\Response;
1818
use Symfony\Component\HttpKernel\Debug\FileLinkFormatter;
1919
use Symfony\Component\HttpKernel\Log\DebugLoggerInterface;
20-
use Symfony\Component\VarDumper\Cloner\VarCloner;
20+
use Symfony\Component\VarDumper\Cloner\Data;
2121
use Symfony\Component\VarDumper\Dumper\HtmlDumper;
2222

2323
/**
@@ -69,7 +69,7 @@ public function render(\Throwable $exception): FlattenException
6969
$headers['X-Debug-Exception-File'] = rawurlencode($exception->getFile()).':'.$exception->getLine();
7070
}
7171

72-
$exception = FlattenException::createFromThrowable($exception, null, $headers);
72+
$exception = FlattenException::createWithDataRepresentation($exception, null, $headers);
7373

7474
return $exception->setAsString($this->renderException($exception));
7575
}
@@ -149,21 +149,12 @@ private function renderException(FlattenException $exception, string $debugTempl
149149
]);
150150
}
151151

152-
private function dumpValue(mixed $value): string
152+
private function dumpValue(Data $value): string
153153
{
154-
$cloner = new VarCloner();
155-
$data = $cloner->cloneVar($value);
156-
157154
$dumper = new HtmlDumper();
158155
$dumper->setTheme('light');
159-
$dumper->setOutput($output = fopen('php://memory', 'r+'));
160-
$dumper->dump($data);
161-
162-
$dump = stream_get_contents($output, -1, 0);
163-
rewind($output);
164-
ftruncate($output, 0);
165156

166-
return $dump;
157+
return $dumper->dump($value, true);
167158
}
168159

169160
private function formatArgs(array $args): string

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

Lines changed: 47 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,10 @@
1414
use Symfony\Component\HttpFoundation\Exception\RequestExceptionInterface;
1515
use Symfony\Component\HttpFoundation\Response;
1616
use Symfony\Component\HttpKernel\Exception\HttpExceptionInterface;
17+
use Symfony\Component\VarDumper\Caster\Caster;
18+
use Symfony\Component\VarDumper\Cloner\Data;
19+
use Symfony\Component\VarDumper\Cloner\Stub;
20+
use Symfony\Component\VarDumper\Cloner\VarCloner;
1721

1822
/**
1923
* FlattenException wraps a PHP Error or Exception to be able to serialize it.
@@ -36,7 +40,7 @@ class FlattenException
3640
private string $file;
3741
private int $line;
3842
private ?string $asString = null;
39-
private array $properties = [];
43+
private Data $dataRepresentation;
4044

4145
public static function create(\Exception $exception, int $statusCode = null, array $headers = []): static
4246
{
@@ -78,14 +82,34 @@ public static function createFromThrowable(\Throwable $exception, int $statusCod
7882
$e->setPrevious(static::createFromThrowable($previous));
7983
}
8084

81-
if ((new \ReflectionClass($exception::class))->isUserDefined()) {
82-
$getProperties = \Closure::bind(fn (\Throwable $e) => get_object_vars($e), null, $exception::class);
83-
$properties = $getProperties($exception);
84-
unset($properties['message'], $properties['code'], $properties['file'], $properties['line']);
85-
$e->properties = $properties;
85+
return $e;
86+
}
87+
88+
public static function createWithDataRepresentation(\Throwable $throwable, int $statusCode = null, array $headers = [], VarCloner $cloner = null): static
89+
{
90+
$e = static::createFromThrowable($throwable, $statusCode, $headers);
91+
92+
static $defaultCloner;
93+
94+
if (!$cloner ??= $defaultCloner) {
95+
$cloner = $defaultCloner = new VarCloner();
96+
$cloner->addCasters([
97+
\Throwable::class => function (\Throwable $e, array $a, Stub $s, bool $isNested): array {
98+
if (!$isNested) {
99+
unset($a[Caster::PREFIX_PROTECTED.'message']);
100+
unset($a[Caster::PREFIX_PROTECTED.'code']);
101+
unset($a[Caster::PREFIX_PROTECTED.'file']);
102+
unset($a[Caster::PREFIX_PROTECTED.'line']);
103+
unset($a["\0Error\0trace"], $a["\0Exception\0trace"]);
104+
unset($a["\0Error\0previous"], $a["\0Exception\0previous"]);
105+
}
106+
107+
return $a;
108+
},
109+
]);
86110
}
87111

88-
return $e;
112+
return $e->setDataRepresentation($cloner->cloneVar($throwable));
89113
}
90114

91115
public function toArray(): array
@@ -96,7 +120,7 @@ public function toArray(): array
96120
'message' => $exception->getMessage(),
97121
'class' => $exception->getClass(),
98122
'trace' => $exception->getTrace(),
99-
'properties' => $exception->getProperties(),
123+
'data' => $exception->getDataRepresentation(),
100124
];
101125
}
102126

@@ -230,11 +254,6 @@ public function setCode(int|string $code): static
230254
return $this;
231255
}
232256

233-
public function getProperties(): array
234-
{
235-
return $this->properties;
236-
}
237-
238257
public function getPrevious(): ?self
239258
{
240259
return $this->previous;
@@ -319,6 +338,21 @@ public function setTrace(array $trace, ?string $file, ?int $line): static
319338
return $this;
320339
}
321340

341+
public function getDataRepresentation(): ?Data
342+
{
343+
return $this->dataRepresentation ?? null;
344+
}
345+
346+
/**
347+
* @return $this
348+
*/
349+
public function setDataRepresentation(Data $data): static
350+
{
351+
$this->dataRepresentation = $data;
352+
353+
return $this;
354+
}
355+
322356
private function flattenArgs(array $args, int $level = 0, int &$count = 0): array
323357
{
324358
$result = [];

src/Symfony/Component/ErrorHandler/Resources/views/traces.html.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,11 +25,11 @@
2525
<p class="break-long-words trace-message"><?= $this->escape($exception['message']); ?></p>
2626
<?php } ?>
2727
</div>
28-
<?php if ($exception['properties']) { ?>
28+
<?php if (\count($exception['data'] ?? [])) { ?>
2929
<details class="exception-properties-wrapper">
3030
<summary>Show exception properties</summary>
3131
<div class="exception-properties">
32-
<?= $this->dumpValue($exception['properties']) ?>
32+
<?= $this->dumpValue($exception['data']) ?>
3333
</div>
3434
</details>
3535
<?php } ?>

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -209,7 +209,7 @@ public function testToArray(\Throwable $exception, string $expectedClass)
209209
'namespace' => '', 'short_class' => '', 'class' => '', 'type' => '', 'function' => '', 'file' => 'foo.php', 'line' => 123,
210210
'args' => [],
211211
]],
212-
'properties' => [],
212+
'data' => null,
213213
],
214214
], $flattened->toArray());
215215
}

src/Symfony/Component/HttpKernel/DataCollector/ExceptionDataCollector.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ public function collect(Request $request, Response $response, \Throwable $except
2626
{
2727
if (null !== $exception) {
2828
$this->data = [
29-
'exception' => FlattenException::createFromThrowable($exception),
29+
'exception' => FlattenException::createWithDataRepresentation($exception),
3030
];
3131
}
3232
}

src/Symfony/Component/HttpKernel/Tests/DataCollector/ExceptionDataCollectorTest.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ public function testCollect()
2323
{
2424
$e = new \Exception('foo', 500);
2525
$c = new ExceptionDataCollector();
26-
$flattened = FlattenException::createFromThrowable($e);
26+
$flattened = FlattenException::createWithDataRepresentation($e);
2727
$trace = $flattened->getTrace();
2828

2929
$this->assertFalse($c->hasException());

src/Symfony/Component/HttpKernel/composer.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@
1818
"require": {
1919
"php": ">=8.1",
2020
"symfony/deprecation-contracts": "^2.5|^3",
21-
"symfony/error-handler": "^6.1",
21+
"symfony/error-handler": "^6.3",
2222
"symfony/event-dispatcher": "^5.4|^6.0",
2323
"symfony/http-foundation": "^5.4.21|^6.2.7",
2424
"symfony/polyfill-ctype": "^1.8",

src/Symfony/Component/VarDumper/Caster/ExceptionCaster.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -306,7 +306,7 @@ private static function filterExceptionArray(string $xClass, array $a, string $x
306306
if (empty($a[$xPrefix.'previous'])) {
307307
unset($a[$xPrefix.'previous']);
308308
}
309-
unset($a[$xPrefix.'string'], $a[Caster::PREFIX_DYNAMIC.'xdebug_message'], $a[Caster::PREFIX_DYNAMIC.'__destructorException']);
309+
unset($a[$xPrefix.'string'], $a[Caster::PREFIX_DYNAMIC.'xdebug_message']);
310310

311311
if (isset($a[Caster::PREFIX_PROTECTED.'message']) && str_contains($a[Caster::PREFIX_PROTECTED.'message'], "@anonymous\0")) {
312312
$a[Caster::PREFIX_PROTECTED.'message'] = preg_replace_callback('/[a-zA-Z_\x7f-\xff][\\\\a-zA-Z0-9_\x7f-\xff]*+@anonymous\x00.*?\.php(?:0x?|:[0-9]++\$)[0-9a-fA-F]++/', fn ($m) => class_exists($m[0], false) ? (get_parent_class($m[0]) ?: key(class_implements($m[0])) ?: 'class').'@anonymous' : $m[0], $a[Caster::PREFIX_PROTECTED.'message']);

src/Symfony/Component/VarDumper/Cloner/VarCloner.php

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,6 @@
1616
*/
1717
class VarCloner extends AbstractCloner
1818
{
19-
private static string $gid;
2019
private static array $arrayCache = [];
2120

2221
protected function doClone(mixed $var): array
@@ -41,7 +40,6 @@ protected function doClone(mixed $var): array
4140
$stub = null; // Stub capturing the main properties of an original item value
4241
// or null if the original value is used directly
4342

44-
$gid = self::$gid ??= hash('xxh128', random_bytes(6)); // Unique string used to detect the special $GLOBALS variable
4543
$arrayStub = new Stub();
4644
$arrayStub->type = Stub::TYPE_ARRAY;
4745
$fromObjCast = false;

0 commit comments

Comments
 (0)