Skip to content

Commit 3e84f7d

Browse files
committed
bug symfony#23413 [VarDumper] Reduce size of serialized Data objects (nicolas-grekas)
This PR was merged into the 3.3 branch. Discussion ---------- [VarDumper] Reduce size of serialized Data objects | Q | A | ------------- | --- | Branch? | 3.3 | Bug fix? | yes | New feature? | no | BC breaks? | no | Deprecations? | no | Tests pass? | no | Fixed tickets | symfony#23233 | License | MIT | Doc PR | - By using `Stub` objects a lot, especially for arrays, `Data` objects generate heavy serialized strings. By implemeting `Serializable` on `Data`, this PR removes most of the boilerplate. This PR also removes duplicate data in `LoggerDataCollector`, and reduces the backtrace of silenced errors to their 3 last items - which should be enough - and is otherwise responsible for a significant portion of the serialized payloads. This is not the last possible step towards shrinking serialized profiles, but the next one is more complex -and maybe this one is good enough? Please give feedback if you can. Commits ------- 70bd2bc [VarDumper] Reduce size of serialized Data objects
2 parents bef2142 + 70bd2bc commit 3e84f7d

File tree

5 files changed

+76
-5
lines changed

5 files changed

+76
-5
lines changed

src/Symfony/Component/Debug/ErrorHandler.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -414,7 +414,7 @@ public function handleError($type, $message, $file, $line)
414414
$errorAsException = self::$silencedErrorCache[$message];
415415
++$errorAsException->count;
416416
} else {
417-
$lightTrace = $this->tracedErrors & $type ? $this->cleanTrace(debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS), $type, $file, $line, false) : array();
417+
$lightTrace = $this->tracedErrors & $type ? $this->cleanTrace(debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS, 3), $type, $file, $line, false) : array();
418418
$errorAsException = new SilencedErrorContext($type, $file, $line, $lightTrace);
419419
}
420420

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

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -120,6 +120,7 @@ private function getContainerDeprecationLogs()
120120
$log['priorityName'] = 'DEBUG';
121121
$log['channel'] = '-';
122122
$log['scream'] = false;
123+
unset($log['type'], $log['file'], $log['line'], $log['trace'], $log['trace'], $log['count']);
123124
$logs[] = $log;
124125
}
125126

@@ -251,7 +252,7 @@ private function computeErrorsCount(array $containerDeprecationLogs)
251252
}
252253

253254
foreach ($containerDeprecationLogs as $deprecationLog) {
254-
$count['deprecation_count'] += $deprecationLog['count'];
255+
$count['deprecation_count'] += $deprecationLog['context']['exception']->count;
255256
}
256257

257258
ksort($count['priorities']);

src/Symfony/Component/HttpKernel/Kernel.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -551,7 +551,7 @@ protected function initializeContainer()
551551
return;
552552
}
553553

554-
$backtrace = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS);
554+
$backtrace = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS, 3);
555555
// Clean the trace by removing first frames added by the error handler itself.
556556
for ($i = 0; isset($backtrace[$i]); ++$i) {
557557
if (isset($backtrace[$i]['file'], $backtrace[$i]['line']) && $backtrace[$i]['line'] === $line && $backtrace[$i]['file'] === $file) {

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ public function testDump()
5050
);
5151
$this->assertEquals($xDump, $dump);
5252

53-
$this->assertStringMatchesFormat('a:3:{i:0;a:5:{s:4:"data";O:39:"Symfony\Component\VarDumper\Cloner\Data":%a', $collector->serialize());
53+
$this->assertStringMatchesFormat('a:3:{i:0;a:5:{s:4:"data";%c:39:"Symfony\Component\VarDumper\Cloner\Data":%a', $collector->serialize());
5454
$this->assertSame(0, $collector->getDumpsCount());
5555
$this->assertSame('a:2:{i:0;b:0;i:1;s:5:"UTF-8";}', $collector->serialize());
5656
}

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

Lines changed: 71 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@
1616
/**
1717
* @author Nicolas Grekas <p@tchwork.com>
1818
*/
19-
class Data implements \ArrayAccess, \Countable, \IteratorAggregate
19+
class Data implements \ArrayAccess, \Countable, \IteratorAggregate, \Serializable
2020
{
2121
private $data;
2222
private $position = 0;
@@ -278,6 +278,57 @@ public function dump(DumperInterface $dumper)
278278
$this->dumpItem($dumper, new Cursor(), $refs, $this->data[$this->position][$this->key]);
279279
}
280280

281+
/**
282+
* @internal
283+
*/
284+
public function serialize()
285+
{
286+
$data = $this->data;
287+
288+
foreach ($data as $i => $values) {
289+
foreach ($values as $k => $v) {
290+
if ($v instanceof Stub) {
291+
if (Stub::TYPE_ARRAY === $v->type) {
292+
$v = self::mapStubConsts($v, false);
293+
$data[$i][$k] = array($v->class, $v->position, $v->cut);
294+
} else {
295+
$v = self::mapStubConsts($v, false);
296+
$data[$i][$k] = array($v->class, $v->position, $v->cut, $v->type, $v->value, $v->handle, $v->refCount, $v->attr);
297+
}
298+
}
299+
}
300+
}
301+
302+
return serialize(array($data, $this->position, $this->key, $this->maxDepth, $this->maxItemsPerDepth, $this->useRefHandles));
303+
}
304+
305+
/**
306+
* @internal
307+
*/
308+
public function unserialize($serialized)
309+
{
310+
list($data, $this->position, $this->key, $this->maxDepth, $this->maxItemsPerDepth, $this->useRefHandles) = unserialize($serialized);
311+
312+
foreach ($data as $i => $values) {
313+
foreach ($values as $k => $v) {
314+
if ($v && is_array($v)) {
315+
$s = new Stub();
316+
if (3 === count($v)) {
317+
$s->type = Stub::TYPE_ARRAY;
318+
$s = self::mapStubConsts($s, false);
319+
list($s->class, $s->position, $s->cut) = $v;
320+
$s->value = $s->cut + count($data[$s->position]);
321+
} else {
322+
list($s->class, $s->position, $s->cut, $s->type, $s->value, $s->handle, $s->refCount, $s->attr) = $v;
323+
}
324+
$data[$i][$k] = self::mapStubConsts($s, true);
325+
}
326+
}
327+
}
328+
329+
$this->data = $data;
330+
}
331+
281332
/**
282333
* Depth-first dumping of items.
283334
*
@@ -406,4 +457,23 @@ private function dumpChildren($dumper, $parentCursor, &$refs, $children, $hashCu
406457

407458
return $hashCut;
408459
}
460+
461+
private static function mapStubConsts(Stub $stub, $resolve)
462+
{
463+
static $stubConstIndexes, $stubConstValues;
464+
465+
if (null === $stubConstIndexes) {
466+
$r = new \ReflectionClass(Stub::class);
467+
$stubConstIndexes = array_flip(array_values($r->getConstants()));
468+
$stubConstValues = array_flip($stubConstIndexes);
469+
}
470+
471+
$map = $resolve ? $stubConstValues : $stubConstIndexes;
472+
473+
$stub = clone $stub;
474+
$stub->type = $map[$stub->type];
475+
$stub->class = isset($map[$stub->class]) ? $map[$stub->class] : $stub->class;
476+
477+
return $stub;
478+
}
409479
}

0 commit comments

Comments
 (0)