[VarDumper][HttpKernel] Enhance perf of ExceptionCaster & DataCollector
This commit is contained in:
parent
cb03103570
commit
be2b7df5c5
@ -42,6 +42,8 @@ abstract class DataCollector implements DataCollectorInterface, \Serializable
|
|||||||
*/
|
*/
|
||||||
private $cloner;
|
private $cloner;
|
||||||
|
|
||||||
|
private static $stubsCache = array();
|
||||||
|
|
||||||
public function serialize()
|
public function serialize()
|
||||||
{
|
{
|
||||||
return serialize($this->data);
|
return serialize($this->data);
|
||||||
@ -124,14 +126,17 @@ abstract class DataCollector implements DataCollectorInterface, \Serializable
|
|||||||
return $var;
|
return $var;
|
||||||
}
|
}
|
||||||
if (is_string($var)) {
|
if (is_string($var)) {
|
||||||
|
if (isset(self::$stubsCache[$var])) {
|
||||||
|
return self::$stubsCache[$var];
|
||||||
|
}
|
||||||
if (false !== strpos($var, '\\')) {
|
if (false !== strpos($var, '\\')) {
|
||||||
$c = (false !== $i = strpos($var, '::')) ? substr($var, 0, $i) : $var;
|
$c = (false !== $i = strpos($var, '::')) ? substr($var, 0, $i) : $var;
|
||||||
if (class_exists($c, false) || interface_exists($c, false) || trait_exists($c, false)) {
|
if (class_exists($c, false) || interface_exists($c, false) || trait_exists($c, false)) {
|
||||||
return new ClassStub($var);
|
return self::$stubsCache[$var] = new ClassStub($var);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (false !== strpos($var, DIRECTORY_SEPARATOR) && false === strpos($var, '://') && false === strpos($var, "\0") && is_file($var)) {
|
if (false !== strpos($var, DIRECTORY_SEPARATOR) && false === strpos($var, '://') && false === strpos($var, "\0") && is_file($var)) {
|
||||||
return new LinkStub($var);
|
return self::$stubsCache[$var] = new LinkStub($var);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -57,15 +57,20 @@ class Caster
|
|||||||
}
|
}
|
||||||
|
|
||||||
if ($a) {
|
if ($a) {
|
||||||
|
$combine = false;
|
||||||
$p = array_keys($a);
|
$p = array_keys($a);
|
||||||
foreach ($p as $i => $k) {
|
foreach ($p as $i => $k) {
|
||||||
if (isset($k[0]) && "\0" !== $k[0] && !$reflector->hasProperty($k)) {
|
if (isset($k[0]) && "\0" !== $k[0] && !$reflector->hasProperty($k)) {
|
||||||
|
$combine = true;
|
||||||
$p[$i] = self::PREFIX_DYNAMIC.$k;
|
$p[$i] = self::PREFIX_DYNAMIC.$k;
|
||||||
} elseif (isset($k[16]) && "\0" === $k[16] && 0 === strpos($k, "\0class@anonymous\0")) {
|
} elseif (isset($k[16]) && "\0" === $k[16] && 0 === strpos($k, "\0class@anonymous\0")) {
|
||||||
|
$combine = true;
|
||||||
$p[$i] = "\0".$reflector->getParentClass().'@anonymous'.strrchr($k, "\0");
|
$p[$i] = "\0".$reflector->getParentClass().'@anonymous'.strrchr($k, "\0");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
$a = array_combine($p, $a);
|
if ($combine) {
|
||||||
|
$a = array_combine($p, $a);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return $a;
|
return $a;
|
||||||
|
@ -41,6 +41,8 @@ class ExceptionCaster
|
|||||||
E_STRICT => 'E_STRICT',
|
E_STRICT => 'E_STRICT',
|
||||||
);
|
);
|
||||||
|
|
||||||
|
private static $framesCache = array();
|
||||||
|
|
||||||
public static function castError(\Error $e, array $a, Stub $stub, $isNested, $filter = 0)
|
public static function castError(\Error $e, array $a, Stub $stub, $isNested, $filter = 0)
|
||||||
{
|
{
|
||||||
return self::filterExceptionArray($stub->class, $a, "\0Error\0", $filter);
|
return self::filterExceptionArray($stub->class, $a, "\0Error\0", $filter);
|
||||||
@ -142,43 +144,52 @@ class ExceptionCaster
|
|||||||
$prefix = Caster::PREFIX_VIRTUAL;
|
$prefix = Caster::PREFIX_VIRTUAL;
|
||||||
|
|
||||||
if (isset($f['file'], $f['line'])) {
|
if (isset($f['file'], $f['line'])) {
|
||||||
if (preg_match('/\((\d+)\)(?:\([\da-f]{32}\))? : (?:eval\(\)\'d code|runtime-created function)$/', $f['file'], $match)) {
|
$cacheKey = $f;
|
||||||
$f['file'] = substr($f['file'], 0, -strlen($match[0]));
|
unset($cacheKey['object'], $cacheKey['args']);
|
||||||
$f['line'] = (int) $match[1];
|
$cacheKey[] = self::$srcContext;
|
||||||
}
|
$cacheKey = implode('-', $cacheKey);
|
||||||
$caller = isset($f['function']) ? sprintf('in %s() on line %d', (isset($f['class']) ? $f['class'].$f['type'] : '').$f['function'], $f['line']) : null;
|
|
||||||
$src = $f['line'];
|
|
||||||
$srcKey = $f['file'];
|
|
||||||
$ellipsis = explode(DIRECTORY_SEPARATOR, $srcKey);
|
|
||||||
$ellipsis = 3 < count($ellipsis) ? 2 + strlen(implode(array_slice($ellipsis, -2))) : 0;
|
|
||||||
|
|
||||||
if (file_exists($f['file']) && 0 <= self::$srcContext) {
|
if (isset(self::$framesCache[$cacheKey])) {
|
||||||
if (!empty($f['class']) && is_subclass_of($f['class'], 'Twig_Template') && method_exists($f['class'], 'getDebugInfo')) {
|
$a[$prefix.'src'] = self::$framesCache[$cacheKey];
|
||||||
$template = isset($f['object']) ? $f['object'] : unserialize(sprintf('O:%d:"%s":0:{}', strlen($f['class']), $f['class']));
|
} else {
|
||||||
|
if (preg_match('/\((\d+)\)(?:\([\da-f]{32}\))? : (?:eval\(\)\'d code|runtime-created function)$/', $f['file'], $match)) {
|
||||||
|
$f['file'] = substr($f['file'], 0, -strlen($match[0]));
|
||||||
|
$f['line'] = (int) $match[1];
|
||||||
|
}
|
||||||
|
$caller = isset($f['function']) ? sprintf('in %s() on line %d', (isset($f['class']) ? $f['class'].$f['type'] : '').$f['function'], $f['line']) : null;
|
||||||
|
$src = $f['line'];
|
||||||
|
$srcKey = $f['file'];
|
||||||
|
$ellipsis = explode(DIRECTORY_SEPARATOR, $srcKey);
|
||||||
|
$ellipsis = 3 < count($ellipsis) ? 2 + strlen(implode(array_slice($ellipsis, -2))) : 0;
|
||||||
|
|
||||||
$ellipsis = 0;
|
if (file_exists($f['file']) && 0 <= self::$srcContext) {
|
||||||
$templateSrc = method_exists($template, 'getSourceContext') ? $template->getSourceContext()->getCode() : (method_exists($template, 'getSource') ? $template->getSource() : '');
|
if (!empty($f['class']) && is_subclass_of($f['class'], 'Twig_Template') && method_exists($f['class'], 'getDebugInfo')) {
|
||||||
$templateInfo = $template->getDebugInfo();
|
$template = isset($f['object']) ? $f['object'] : unserialize(sprintf('O:%d:"%s":0:{}', strlen($f['class']), $f['class']));
|
||||||
if (isset($templateInfo[$f['line']])) {
|
|
||||||
$templatePath = method_exists($template, 'getSourceContext') ? $template->getSourceContext()->getPath() : null;
|
|
||||||
|
|
||||||
if ($templateSrc) {
|
$ellipsis = 0;
|
||||||
$templateSrc = explode("\n", $templateSrc);
|
$templateSrc = method_exists($template, 'getSourceContext') ? $template->getSourceContext()->getCode() : (method_exists($template, 'getSource') ? $template->getSource() : '');
|
||||||
$src = self::extractSource($templateSrc, $templateInfo[$f['line']], self::$srcContext, $caller, 'twig', $templatePath);
|
$templateInfo = $template->getDebugInfo();
|
||||||
$srcKey = ($templatePath ?: $template->getTemplateName()).':'.$templateInfo[$f['line']];
|
if (isset($templateInfo[$f['line']])) {
|
||||||
|
if (!method_exists($template, 'getSourceContext') || !file_exists($templatePath = $template->getSourceContext()->getPath())) {
|
||||||
|
$templatePath = null;
|
||||||
|
}
|
||||||
|
if ($templateSrc) {
|
||||||
|
$src = self::extractSource($templateSrc, $templateInfo[$f['line']], self::$srcContext, $caller, 'twig', $templatePath);
|
||||||
|
$srcKey = ($templatePath ?: $template->getTemplateName()).':'.$templateInfo[$f['line']];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if ($srcKey == $f['file']) {
|
||||||
|
$src = self::extractSource(file_get_contents($f['file']), $f['line'], self::$srcContext, $caller, 'php', $f['file']);
|
||||||
|
$srcKey .= ':'.$f['line'];
|
||||||
|
if ($ellipsis) {
|
||||||
|
$ellipsis += 1 + strlen($f['line']);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if ($srcKey == $f['file']) {
|
$srcAttr = $ellipsis ? 'ellipsis='.$ellipsis : '';
|
||||||
$src = self::extractSource(explode("\n", file_get_contents($f['file'])), $f['line'], self::$srcContext, $caller, 'php', $f['file']);
|
self::$framesCache[$cacheKey] = $a[$prefix.'src'] = new EnumStub(array("\0~$srcAttr\0$srcKey" => $src));
|
||||||
$srcKey .= ':'.$f['line'];
|
|
||||||
if ($ellipsis) {
|
|
||||||
$ellipsis += 1 + strlen($f['line']);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
$srcAttr = $ellipsis ? 'ellipsis='.$ellipsis : '';
|
|
||||||
$a[$prefix.'src'] = new EnumStub(array("\0~$srcAttr\0$srcKey" => $src));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
unset($a[$prefix.'args'], $a[$prefix.'line'], $a[$prefix.'file']);
|
unset($a[$prefix.'args'], $a[$prefix.'line'], $a[$prefix.'file']);
|
||||||
@ -232,14 +243,16 @@ class ExceptionCaster
|
|||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
private static function extractSource(array $srcArray, $line, $srcContext, $title, $lang, $file = null)
|
private static function extractSource($srcLines, $line, $srcContext, $title, $lang, $file = null)
|
||||||
{
|
{
|
||||||
|
$srcLines = explode("\n", $srcLines);
|
||||||
$src = array();
|
$src = array();
|
||||||
|
|
||||||
for ($i = $line - 1 - $srcContext; $i <= $line - 1 + $srcContext; ++$i) {
|
for ($i = $line - 1 - $srcContext; $i <= $line - 1 + $srcContext; ++$i) {
|
||||||
$src[] = (isset($srcArray[$i]) ? $srcArray[$i] : '')."\n";
|
$src[] = (isset($srcLines[$i]) ? $srcLines[$i] : '')."\n";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$srcLines = array();
|
||||||
$ltrim = 0;
|
$ltrim = 0;
|
||||||
do {
|
do {
|
||||||
$pad = null;
|
$pad = null;
|
||||||
@ -257,7 +270,6 @@ class ExceptionCaster
|
|||||||
} while (0 > $i && null !== $pad);
|
} while (0 > $i && null !== $pad);
|
||||||
|
|
||||||
--$ltrim;
|
--$ltrim;
|
||||||
$srcArray = array();
|
|
||||||
|
|
||||||
foreach ($src as $i => $c) {
|
foreach ($src as $i => $c) {
|
||||||
if ($ltrim) {
|
if ($ltrim) {
|
||||||
@ -274,9 +286,9 @@ class ExceptionCaster
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
$c->attr['lang'] = $lang;
|
$c->attr['lang'] = $lang;
|
||||||
$srcArray[sprintf("\0~%d\0", $i + $line - $srcContext)] = $c;
|
$srcLines[sprintf("\0~%d\0", $i + $line - $srcContext)] = $c;
|
||||||
}
|
}
|
||||||
|
|
||||||
return new EnumStub($srcArray);
|
return new EnumStub($srcLines);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -252,14 +252,15 @@ abstract class AbstractCloner implements ClonerInterface
|
|||||||
new \ReflectionClass($class),
|
new \ReflectionClass($class),
|
||||||
array_reverse(array($class => $class) + class_parents($class) + class_implements($class) + array('*' => '*')),
|
array_reverse(array($class => $class) + class_parents($class) + class_implements($class) + array('*' => '*')),
|
||||||
);
|
);
|
||||||
|
$classInfo[1] = array_map('strtolower', $classInfo[1]);
|
||||||
|
|
||||||
$this->classInfo[$class] = $classInfo;
|
$this->classInfo[$class] = $classInfo;
|
||||||
}
|
}
|
||||||
|
|
||||||
$a = $this->callCaster('Symfony\Component\VarDumper\Caster\Caster::castObject', $obj, $classInfo[0], null, $isNested);
|
$a = Caster::castObject($obj, $classInfo[0]);
|
||||||
|
|
||||||
foreach ($classInfo[1] as $p) {
|
foreach ($classInfo[1] as $p) {
|
||||||
if (!empty($this->casters[$p = strtolower($p)])) {
|
if (!empty($this->casters[$p])) {
|
||||||
foreach ($this->casters[$p] as $p) {
|
foreach ($this->casters[$p] as $p) {
|
||||||
$a = $this->callCaster($p, $obj, $a, $stub, $isNested);
|
$a = $this->callCaster($p, $obj, $a, $stub, $isNested);
|
||||||
}
|
}
|
||||||
|
@ -179,14 +179,14 @@ EODUMP;
|
|||||||
$f = array(
|
$f = array(
|
||||||
new FrameStub(array(
|
new FrameStub(array(
|
||||||
'file' => dirname(__DIR__).'/Fixtures/Twig.php',
|
'file' => dirname(__DIR__).'/Fixtures/Twig.php',
|
||||||
'line' => 21,
|
'line' => 20,
|
||||||
'class' => '__TwigTemplate_VarDumperFixture_u75a09',
|
'class' => '__TwigTemplate_VarDumperFixture_u75a09',
|
||||||
)),
|
)),
|
||||||
new FrameStub(array(
|
new FrameStub(array(
|
||||||
'file' => dirname(__DIR__).'/Fixtures/Twig.php',
|
'file' => dirname(__DIR__).'/Fixtures/Twig.php',
|
||||||
'line' => 21,
|
'line' => 21,
|
||||||
'class' => '__TwigTemplate_VarDumperFixture_u75a09',
|
'class' => '__TwigTemplate_VarDumperFixture_u75a09',
|
||||||
'object' => new \__TwigTemplate_VarDumperFixture_u75a09(null, false),
|
'object' => new \__TwigTemplate_VarDumperFixture_u75a09(null, __FILE__),
|
||||||
)),
|
)),
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -195,10 +195,10 @@ array:2 [
|
|||||||
0 => {
|
0 => {
|
||||||
class: "__TwigTemplate_VarDumperFixture_u75a09"
|
class: "__TwigTemplate_VarDumperFixture_u75a09"
|
||||||
src: {
|
src: {
|
||||||
bar.twig:2: {
|
%sTwig.php:1: {
|
||||||
|
:
|
||||||
: foo bar
|
: foo bar
|
||||||
: twig source
|
: twig source
|
||||||
:
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -208,7 +208,7 @@ array:2 [
|
|||||||
%A
|
%A
|
||||||
}
|
}
|
||||||
src: {
|
src: {
|
||||||
foo.twig:2: {
|
%sExceptionCasterTest.php:2: {
|
||||||
: foo bar
|
: foo bar
|
||||||
: twig source
|
: twig source
|
||||||
:
|
:
|
||||||
|
@ -271,7 +271,7 @@ stream resource {@{$ref}
|
|||||||
⚠: Symfony\Component\VarDumper\Exception\ThrowingCasterException {{$r}
|
⚠: Symfony\Component\VarDumper\Exception\ThrowingCasterException {{$r}
|
||||||
#message: "Unexpected Exception thrown from a caster: Foobar"
|
#message: "Unexpected Exception thrown from a caster: Foobar"
|
||||||
-trace: {
|
-trace: {
|
||||||
bar.twig:%d: {
|
%sTwig.php:2: {
|
||||||
: foo bar
|
: foo bar
|
||||||
: twig source
|
: twig source
|
||||||
:
|
:
|
||||||
|
@ -3,16 +3,16 @@
|
|||||||
/* foo.twig */
|
/* foo.twig */
|
||||||
class __TwigTemplate_VarDumperFixture_u75a09 extends Twig_Template
|
class __TwigTemplate_VarDumperFixture_u75a09 extends Twig_Template
|
||||||
{
|
{
|
||||||
private $filename;
|
private $path;
|
||||||
|
|
||||||
public function __construct(Twig_Environment $env = null, $filename = null)
|
public function __construct(Twig_Environment $env = null, $path = null)
|
||||||
{
|
{
|
||||||
if (null !== $env) {
|
if (null !== $env) {
|
||||||
parent::__construct($env);
|
parent::__construct($env);
|
||||||
}
|
}
|
||||||
$this->parent = false;
|
$this->parent = false;
|
||||||
$this->blocks = array();
|
$this->blocks = array();
|
||||||
$this->filename = $filename;
|
$this->path = $path;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function doDisplay(array $context, array $blocks = array())
|
protected function doDisplay(array $context, array $blocks = array())
|
||||||
@ -28,11 +28,11 @@ class __TwigTemplate_VarDumperFixture_u75a09 extends Twig_Template
|
|||||||
|
|
||||||
public function getDebugInfo()
|
public function getDebugInfo()
|
||||||
{
|
{
|
||||||
return array(21 => 2);
|
return array(20 => 1, 21 => 2);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getSourceContext()
|
public function getSourceContext()
|
||||||
{
|
{
|
||||||
return new Twig_Source(" foo bar\n twig source\n\n", 'foo.twig', false === $this->filename ? null : ($this->filename ?: 'bar.twig'));
|
return new Twig_Source(" foo bar\n twig source\n\n", 'foo.twig', $this->path ?: __FILE__);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user