[VarDumper] display the signature of callables

This commit is contained in:
Nicolas Grekas 2018-06-29 10:21:45 +02:00
parent 0e9ded3188
commit 73b4ac78c0
7 changed files with 77 additions and 13 deletions

View File

@ -11,6 +11,8 @@
namespace Symfony\Component\VarDumper\Caster;
use Symfony\Component\VarDumper\Cloner\Stub;
/**
* Represents a PHP class identifier.
*
@ -58,6 +60,20 @@ class ClassStub extends ConstStub
$r = new \ReflectionClass($r[0]);
}
}
if (null !== $callable && $r instanceof \ReflectionFunctionAbstract) {
$s = ReflectionCaster::castFunctionAbstract($r, array(), new Stub(), true);
$s = ReflectionCaster::getSignature($s);
if ('()' === substr($identifier, -2)) {
$this->value = substr_replace($identifier, $s, -2);
} else {
$this->value .= $s;
}
if (isset($this->attr['ellipsis'])) {
$this->attr['ellipsis'] += \strlen($this->value) - \strlen($identifier);
}
}
} catch (\ReflectionException $e) {
return;
}
@ -75,9 +91,9 @@ class ClassStub extends ConstStub
}
if (!is_array($callable)) {
$callable = new static($callable);
$callable = new static($callable, $callable);
} elseif (is_string($callable[0])) {
$callable[0] = new static($callable[0]);
$callable[0] = new static($callable[0], $callable);
} else {
$callable[1] = new static($callable[1], $callable);
}

View File

@ -38,6 +38,8 @@ class ReflectionCaster
$a = static::castFunctionAbstract($c, $a, $stub, $isNested, $filter);
$stub->class .= self::getSignature($a);
if (isset($a[$prefix.'parameters'])) {
foreach ($a[$prefix.'parameters']->value as &$v) {
$param = $v;
@ -294,6 +296,52 @@ class ReflectionCaster
return $a;
}
public static function getSignature(array $a)
{
$prefix = Caster::PREFIX_VIRTUAL;
$signature = '';
if (isset($a[$prefix.'parameters'])) {
foreach ($a[$prefix.'parameters']->value as $k => $param) {
$signature .= ', ';
if ($type = $param->getType()) {
if (!$param->isOptional() && $param->allowsNull()) {
$signature .= '?';
}
$signature .= substr(strrchr('\\'.$type->getName(), '\\'), 1).' ';
}
$signature .= $k;
if (!$param->isDefaultValueAvailable()) {
continue;
}
$v = $param->getDefaultValue();
$signature .= ' = ';
if ($param->isDefaultValueConstant()) {
$signature .= substr(strrchr('\\'.$param->getDefaultValueConstantName(), '\\'), 1);
} elseif (null === $v) {
$signature .= 'null';
} elseif (\is_array($v)) {
$signature .= $v ? '[…'.\count($v).']' : '[]';
} elseif (\is_string($v)) {
$signature .= 10 > \strlen($v) && false === strpos($v, '\\') ? "'{$v}'" : "'…".\strlen($v)."'";
} elseif (\is_bool($v)) {
$signature .= $v ? 'true' : 'false';
} else {
$signature .= $v;
}
}
}
$signature = '('.substr($signature, 2).')';
if (isset($a[$prefix.'returnType'])) {
$signature .= ': '.substr(strrchr('\\'.$a[$prefix.'returnType'], '\\'), 1);
}
return $signature;
}
private static function addExtra(&$a, \Reflector $c)
{
$x = isset($a[Caster::PREFIX_VIRTUAL.'extra']) ? $a[Caster::PREFIX_VIRTUAL.'extra']->value : array();

View File

@ -68,14 +68,14 @@ EOTXT
$var = function ($x) use ($a, &$b) {};
$this->assertDumpMatchesFormat(
<<<EOTXT
Closure {
<<<'EOTXT'
Closure($x) {
%Aparameters: {
\$x: {}
$x: {}
}
use: {
\$a: 123
\$b: & 123
$a: 123
$b: & 123
}
file: "%sReflectionCasterTest.php"
line: "68 to 68"
@ -90,7 +90,7 @@ EOTXT
$var = function () {};
$expectedDump = <<<EOTXT
Closure {
Closure() {
class: "Symfony\Component\VarDumper\Tests\Caster\ReflectionCasterTest"
this: Symfony\Component\VarDumper\Tests\Caster\ReflectionCasterTest { }
}
@ -140,7 +140,7 @@ EOTXT
$this->assertDumpMatchesFormat(
<<<EOTXT
Closure {
Closure(): int {
returnType: "int"
class: "Symfony\Component\VarDumper\Tests\Caster\ReflectionCasterTest"
this: Symfony\Component\VarDumper\Tests\Caster\ReflectionCasterTest { }

View File

@ -141,7 +141,7 @@ EODUMP;
$expectedDump = <<<'EODUMP'
<foo></foo><bar><span class=sf-dump-note>array:1</span> [<samp>
<span class=sf-dump-index>0</span> => "<a href="%sFooInterface.php:10" rel="noopener noreferrer"><span class=sf-dump-str title="5 characters">hello</span></a>"
<span class=sf-dump-index>0</span> => "<a href="%sFooInterface.php:10" rel="noopener noreferrer"><span class=sf-dump-str title="39 characters">hello(?stdClass $a, stdClass $b = null)</span></a>"
</samp>]
</bar>
EODUMP;

View File

@ -75,7 +75,7 @@ array:24 [
+foo: "foo"
+"bar": "bar"
}
"closure" => Closure {#%d
"closure" => Closure(\$a, PDO &\$b = null) {#%d
class: "Symfony\Component\VarDumper\Tests\Dumper\CliDumperTest"
this: Symfony\Component\VarDumper\Tests\Dumper\CliDumperTest {#%d …}
parameters: {

View File

@ -78,7 +78,7 @@ class HtmlDumperTest extends TestCase
+<span class=sf-dump-public title="Public property">foo</span>: "<span class=sf-dump-str title="3 characters">foo</span>"
+"<span class=sf-dump-public title="Runtime added dynamic property">bar</span>": "<span class=sf-dump-str title="3 characters">bar</span>"
</samp>}
"<span class=sf-dump-key>closure</span>" => <span class=sf-dump-note>Closure</span> {<a class=sf-dump-ref>#%d</a><samp>
"<span class=sf-dump-key>closure</span>" => <span class=sf-dump-note>Closure(\$a, PDO &amp;\$b = null)</span> {<a class=sf-dump-ref>#%d</a><samp>
<span class=sf-dump-meta>class</span>: "<span class=sf-dump-str title="Symfony\Component\VarDumper\Tests\Dumper\HtmlDumperTest
55 characters"><span class="sf-dump-ellipsis sf-dump-ellipsis-class">Symfony\Component\VarDumper\Tests\Dumper</span><span class=sf-dump-ellipsis>\</span>HtmlDumperTest</span>"
<span class=sf-dump-meta>this</span>: <abbr title="Symfony\Component\VarDumper\Tests\Dumper\HtmlDumperTest" class=sf-dump-note>HtmlDumperTest</abbr> {<a class=sf-dump-ref>#%d</a> &%s;}

View File

@ -7,5 +7,5 @@ interface FooInterface
/**
* Hello.
*/
public function foo();
public function foo(?\stdClass $a, \stdClass $b = null);
}