Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Commit ee4ae55

Browse filesBrowse files
committed
minor symfony#20675 [VarDumper][HttpKernel] Enhance perf of ExceptionCaster & DataCollector (nicolas-grekas)
This PR was merged into the 3.2 branch. Discussion ---------- [VarDumper][HttpKernel] Enhance perf of ExceptionCaster & DataCollector | Q | A | ------------- | --- | Branch? | 3.2 | Bug fix? | yes | New feature? | no | BC breaks? | no | Deprecations? | no | Tests pass? | yes | Fixed tickets | - | License | MIT | Doc PR | - In **dev** on 3.2 , serializing collectors' data is slow because VarDumper is called so many times. Here is a PR to make it a bit faster, with its Blackfire profile: https://blackfire.io/profiles/compare/6f0fdc7a-9157-4dad-bee4-4c98a96184b2/graph Note that it is possible to make things fast again by replacing these multiple calls by a single one juste before serializing the data. Yet, it's not trivial and VarDumper misses a few features to allow dealing with an unserialized Data object and make it look like a real data structure to other code. I'll look at it for 3.3. Commits ------- be2b7df [VarDumper][HttpKernel] Enhance perf of ExceptionCaster & DataCollector
2 parents cb03103 + be2b7df commit ee4ae55
Copy full SHA for ee4ae55

File tree

Expand file treeCollapse file tree

7 files changed

+76
-53
lines changed
Filter options
Expand file treeCollapse file tree

7 files changed

+76
-53
lines changed

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

Copy file name to clipboardExpand all lines: src/Symfony/Component/HttpKernel/DataCollector/DataCollector.php
+7-2Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,8 @@ abstract class DataCollector implements DataCollectorInterface, \Serializable
4242
*/
4343
private $cloner;
4444

45+
private static $stubsCache = array();
46+
4547
public function serialize()
4648
{
4749
return serialize($this->data);
@@ -124,14 +126,17 @@ private function decorateVar($var)
124126
return $var;
125127
}
126128
if (is_string($var)) {
129+
if (isset(self::$stubsCache[$var])) {
130+
return self::$stubsCache[$var];
131+
}
127132
if (false !== strpos($var, '\\')) {
128133
$c = (false !== $i = strpos($var, '::')) ? substr($var, 0, $i) : $var;
129134
if (class_exists($c, false) || interface_exists($c, false) || trait_exists($c, false)) {
130-
return new ClassStub($var);
135+
return self::$stubsCache[$var] = new ClassStub($var);
131136
}
132137
}
133138
if (false !== strpos($var, DIRECTORY_SEPARATOR) && false === strpos($var, '://') && false === strpos($var, "\0") && is_file($var)) {
134-
return new LinkStub($var);
139+
return self::$stubsCache[$var] = new LinkStub($var);
135140
}
136141
}
137142

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

Copy file name to clipboardExpand all lines: src/Symfony/Component/VarDumper/Caster/Caster.php
+6-1Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -57,15 +57,20 @@ public static function castObject($obj, \ReflectionClass $reflector)
5757
}
5858

5959
if ($a) {
60+
$combine = false;
6061
$p = array_keys($a);
6162
foreach ($p as $i => $k) {
6263
if (isset($k[0]) && "\0" !== $k[0] && !$reflector->hasProperty($k)) {
64+
$combine = true;
6365
$p[$i] = self::PREFIX_DYNAMIC.$k;
6466
} elseif (isset($k[16]) && "\0" === $k[16] && 0 === strpos($k, "\0class@anonymous\0")) {
67+
$combine = true;
6568
$p[$i] = "\0".$reflector->getParentClass().'@anonymous'.strrchr($k, "\0");
6669
}
6770
}
68-
$a = array_combine($p, $a);
71+
if ($combine) {
72+
$a = array_combine($p, $a);
73+
}
6974
}
7075

7176
return $a;

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

Copy file name to clipboardExpand all lines: src/Symfony/Component/VarDumper/Caster/ExceptionCaster.php
+49-37Lines changed: 49 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,8 @@ class ExceptionCaster
4141
E_STRICT => 'E_STRICT',
4242
);
4343

44+
private static $framesCache = array();
45+
4446
public static function castError(\Error $e, array $a, Stub $stub, $isNested, $filter = 0)
4547
{
4648
return self::filterExceptionArray($stub->class, $a, "\0Error\0", $filter);
@@ -142,43 +144,52 @@ public static function castFrameStub(FrameStub $frame, array $a, Stub $stub, $is
142144
$prefix = Caster::PREFIX_VIRTUAL;
143145

144146
if (isset($f['file'], $f['line'])) {
145-
if (preg_match('/\((\d+)\)(?:\([\da-f]{32}\))? : (?:eval\(\)\'d code|runtime-created function)$/', $f['file'], $match)) {
146-
$f['file'] = substr($f['file'], 0, -strlen($match[0]));
147-
$f['line'] = (int) $match[1];
148-
}
149-
$caller = isset($f['function']) ? sprintf('in %s() on line %d', (isset($f['class']) ? $f['class'].$f['type'] : '').$f['function'], $f['line']) : null;
150-
$src = $f['line'];
151-
$srcKey = $f['file'];
152-
$ellipsis = explode(DIRECTORY_SEPARATOR, $srcKey);
153-
$ellipsis = 3 < count($ellipsis) ? 2 + strlen(implode(array_slice($ellipsis, -2))) : 0;
154-
155-
if (file_exists($f['file']) && 0 <= self::$srcContext) {
156-
if (!empty($f['class']) && is_subclass_of($f['class'], 'Twig_Template') && method_exists($f['class'], 'getDebugInfo')) {
157-
$template = isset($f['object']) ? $f['object'] : unserialize(sprintf('O:%d:"%s":0:{}', strlen($f['class']), $f['class']));
158-
159-
$ellipsis = 0;
160-
$templateSrc = method_exists($template, 'getSourceContext') ? $template->getSourceContext()->getCode() : (method_exists($template, 'getSource') ? $template->getSource() : '');
161-
$templateInfo = $template->getDebugInfo();
162-
if (isset($templateInfo[$f['line']])) {
163-
$templatePath = method_exists($template, 'getSourceContext') ? $template->getSourceContext()->getPath() : null;
164-
165-
if ($templateSrc) {
166-
$templateSrc = explode("\n", $templateSrc);
167-
$src = self::extractSource($templateSrc, $templateInfo[$f['line']], self::$srcContext, $caller, 'twig', $templatePath);
168-
$srcKey = ($templatePath ?: $template->getTemplateName()).':'.$templateInfo[$f['line']];
147+
$cacheKey = $f;
148+
unset($cacheKey['object'], $cacheKey['args']);
149+
$cacheKey[] = self::$srcContext;
150+
$cacheKey = implode('-', $cacheKey);
151+
152+
if (isset(self::$framesCache[$cacheKey])) {
153+
$a[$prefix.'src'] = self::$framesCache[$cacheKey];
154+
} else {
155+
if (preg_match('/\((\d+)\)(?:\([\da-f]{32}\))? : (?:eval\(\)\'d code|runtime-created function)$/', $f['file'], $match)) {
156+
$f['file'] = substr($f['file'], 0, -strlen($match[0]));
157+
$f['line'] = (int) $match[1];
158+
}
159+
$caller = isset($f['function']) ? sprintf('in %s() on line %d', (isset($f['class']) ? $f['class'].$f['type'] : '').$f['function'], $f['line']) : null;
160+
$src = $f['line'];
161+
$srcKey = $f['file'];
162+
$ellipsis = explode(DIRECTORY_SEPARATOR, $srcKey);
163+
$ellipsis = 3 < count($ellipsis) ? 2 + strlen(implode(array_slice($ellipsis, -2))) : 0;
164+
165+
if (file_exists($f['file']) && 0 <= self::$srcContext) {
166+
if (!empty($f['class']) && is_subclass_of($f['class'], 'Twig_Template') && method_exists($f['class'], 'getDebugInfo')) {
167+
$template = isset($f['object']) ? $f['object'] : unserialize(sprintf('O:%d:"%s":0:{}', strlen($f['class']), $f['class']));
168+
169+
$ellipsis = 0;
170+
$templateSrc = method_exists($template, 'getSourceContext') ? $template->getSourceContext()->getCode() : (method_exists($template, 'getSource') ? $template->getSource() : '');
171+
$templateInfo = $template->getDebugInfo();
172+
if (isset($templateInfo[$f['line']])) {
173+
if (!method_exists($template, 'getSourceContext') || !file_exists($templatePath = $template->getSourceContext()->getPath())) {
174+
$templatePath = null;
175+
}
176+
if ($templateSrc) {
177+
$src = self::extractSource($templateSrc, $templateInfo[$f['line']], self::$srcContext, $caller, 'twig', $templatePath);
178+
$srcKey = ($templatePath ?: $template->getTemplateName()).':'.$templateInfo[$f['line']];
179+
}
169180
}
170181
}
171-
}
172-
if ($srcKey == $f['file']) {
173-
$src = self::extractSource(explode("\n", file_get_contents($f['file'])), $f['line'], self::$srcContext, $caller, 'php', $f['file']);
174-
$srcKey .= ':'.$f['line'];
175-
if ($ellipsis) {
176-
$ellipsis += 1 + strlen($f['line']);
182+
if ($srcKey == $f['file']) {
183+
$src = self::extractSource(file_get_contents($f['file']), $f['line'], self::$srcContext, $caller, 'php', $f['file']);
184+
$srcKey .= ':'.$f['line'];
185+
if ($ellipsis) {
186+
$ellipsis += 1 + strlen($f['line']);
187+
}
177188
}
178189
}
190+
$srcAttr = $ellipsis ? 'ellipsis='.$ellipsis : '';
191+
self::$framesCache[$cacheKey] = $a[$prefix.'src'] = new EnumStub(array("\0~$srcAttr\0$srcKey" => $src));
179192
}
180-
$srcAttr = $ellipsis ? 'ellipsis='.$ellipsis : '';
181-
$a[$prefix.'src'] = new EnumStub(array("\0~$srcAttr\0$srcKey" => $src));
182193
}
183194

184195
unset($a[$prefix.'args'], $a[$prefix.'line'], $a[$prefix.'file']);
@@ -232,14 +243,16 @@ private static function traceUnshift(&$trace, $class, $file, $line)
232243
));
233244
}
234245

235-
private static function extractSource(array $srcArray, $line, $srcContext, $title, $lang, $file = null)
246+
private static function extractSource($srcLines, $line, $srcContext, $title, $lang, $file = null)
236247
{
248+
$srcLines = explode("\n", $srcLines);
237249
$src = array();
238250

239251
for ($i = $line - 1 - $srcContext; $i <= $line - 1 + $srcContext; ++$i) {
240-
$src[] = (isset($srcArray[$i]) ? $srcArray[$i] : '')."\n";
252+
$src[] = (isset($srcLines[$i]) ? $srcLines[$i] : '')."\n";
241253
}
242254

255+
$srcLines = array();
243256
$ltrim = 0;
244257
do {
245258
$pad = null;
@@ -257,7 +270,6 @@ private static function extractSource(array $srcArray, $line, $srcContext, $titl
257270
} while (0 > $i && null !== $pad);
258271

259272
--$ltrim;
260-
$srcArray = array();
261273

262274
foreach ($src as $i => $c) {
263275
if ($ltrim) {
@@ -274,9 +286,9 @@ private static function extractSource(array $srcArray, $line, $srcContext, $titl
274286
}
275287
}
276288
$c->attr['lang'] = $lang;
277-
$srcArray[sprintf("\0~%d\0", $i + $line - $srcContext)] = $c;
289+
$srcLines[sprintf("\0~%d\0", $i + $line - $srcContext)] = $c;
278290
}
279291

280-
return new EnumStub($srcArray);
292+
return new EnumStub($srcLines);
281293
}
282294
}

‎src/Symfony/Component/VarDumper/Cloner/AbstractCloner.php

Copy file name to clipboardExpand all lines: src/Symfony/Component/VarDumper/Cloner/AbstractCloner.php
+3-2Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -252,14 +252,15 @@ protected function castObject(Stub $stub, $isNested)
252252
new \ReflectionClass($class),
253253
array_reverse(array($class => $class) + class_parents($class) + class_implements($class) + array('*' => '*')),
254254
);
255+
$classInfo[1] = array_map('strtolower', $classInfo[1]);
255256

256257
$this->classInfo[$class] = $classInfo;
257258
}
258259

259-
$a = $this->callCaster('Symfony\Component\VarDumper\Caster\Caster::castObject', $obj, $classInfo[0], null, $isNested);
260+
$a = Caster::castObject($obj, $classInfo[0]);
260261

261262
foreach ($classInfo[1] as $p) {
262-
if (!empty($this->casters[$p = strtolower($p)])) {
263+
if (!empty($this->casters[$p])) {
263264
foreach ($this->casters[$p] as $p) {
264265
$a = $this->callCaster($p, $obj, $a, $stub, $isNested);
265266
}

‎src/Symfony/Component/VarDumper/Tests/Caster/ExceptionCasterTest.php

Copy file name to clipboardExpand all lines: src/Symfony/Component/VarDumper/Tests/Caster/ExceptionCasterTest.php
+5-5Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -179,14 +179,14 @@ public function testFrameWithTwig()
179179
$f = array(
180180
new FrameStub(array(
181181
'file' => dirname(__DIR__).'/Fixtures/Twig.php',
182-
'line' => 21,
182+
'line' => 20,
183183
'class' => '__TwigTemplate_VarDumperFixture_u75a09',
184184
)),
185185
new FrameStub(array(
186186
'file' => dirname(__DIR__).'/Fixtures/Twig.php',
187187
'line' => 21,
188188
'class' => '__TwigTemplate_VarDumperFixture_u75a09',
189-
'object' => new \__TwigTemplate_VarDumperFixture_u75a09(null, false),
189+
'object' => new \__TwigTemplate_VarDumperFixture_u75a09(null, __FILE__),
190190
)),
191191
);
192192

@@ -195,10 +195,10 @@ public function testFrameWithTwig()
195195
0 => {
196196
class: "__TwigTemplate_VarDumperFixture_u75a09"
197197
src: {
198-
bar.twig:2: {
198+
%sTwig.php:1: {
199+
:
199200
: foo bar
200201
: twig source
201-
:
202202
}
203203
}
204204
}
@@ -208,7 +208,7 @@ class: "__TwigTemplate_VarDumperFixture_u75a09"
208208
%A
209209
}
210210
src: {
211-
foo.twig:2: {
211+
%sExceptionCasterTest.php:2: {
212212
: foo bar
213213
: twig source
214214
:

‎src/Symfony/Component/VarDumper/Tests/CliDumperTest.php

Copy file name to clipboardExpand all lines: src/Symfony/Component/VarDumper/Tests/CliDumperTest.php
+1-1Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -271,7 +271,7 @@ public function testThrowingCaster()
271271
⚠: Symfony\Component\VarDumper\Exception\ThrowingCasterException {{$r}
272272
#message: "Unexpected Exception thrown from a caster: Foobar"
273273
-trace: {
274-
bar.twig:%d: {
274+
%sTwig.php:2: {
275275
: foo bar
276276
: twig source
277277
:

‎src/Symfony/Component/VarDumper/Tests/Fixtures/Twig.php

Copy file name to clipboardExpand all lines: src/Symfony/Component/VarDumper/Tests/Fixtures/Twig.php
+5-5Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,16 +3,16 @@
33
/* foo.twig */
44
class __TwigTemplate_VarDumperFixture_u75a09 extends Twig_Template
55
{
6-
private $filename;
6+
private $path;
77

8-
public function __construct(Twig_Environment $env = null, $filename = null)
8+
public function __construct(Twig_Environment $env = null, $path = null)
99
{
1010
if (null !== $env) {
1111
parent::__construct($env);
1212
}
1313
$this->parent = false;
1414
$this->blocks = array();
15-
$this->filename = $filename;
15+
$this->path = $path;
1616
}
1717

1818
protected function doDisplay(array $context, array $blocks = array())
@@ -28,11 +28,11 @@ public function getTemplateName()
2828

2929
public function getDebugInfo()
3030
{
31-
return array(21 => 2);
31+
return array(20 => 1, 21 => 2);
3232
}
3333

3434
public function getSourceContext()
3535
{
36-
return new Twig_Source(" foo bar\n twig source\n\n", 'foo.twig', false === $this->filename ? null : ($this->filename ?: 'bar.twig'));
36+
return new Twig_Source(" foo bar\n twig source\n\n", 'foo.twig', $this->path ?: __FILE__);
3737
}
3838
}

0 commit comments

Comments
0 (0)
Morty Proxy This is a proxified and sanitized view of the page, visit original site.