Skip to content

Commit

Permalink
bug #29054 [VarDumper] fix dump of closures created from callables (n…
Browse files Browse the repository at this point in the history
…icolas-grekas)

This PR was merged into the 3.4 branch.

Discussion
----------

[VarDumper] fix dump of closures created from callables

| Q             | A
| ------------- | ---
| Branch?       | 3.4
| Bug fix?      | yes
| New feature?  | no
| BC breaks?    | no
| Deprecations? | no
| Tests pass?   | yes
| Fixed tickets | -
| License       | MIT
| Doc PR        | -

We are missing displaying full information about closures created using `ReflectionMethod::getClosure()` or `Closure::fromCallable()`.

This PR fixes it. For VarDumper but also other places where we have logic to display them.

Commits
-------

1c1818b [VarDumper] fix dump of closures created from callables
  • Loading branch information
nicolas-grekas committed Nov 6, 2018
2 parents 85df96a + 1c1818b commit 41eaba5
Show file tree
Hide file tree
Showing 11 changed files with 124 additions and 13 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -368,6 +368,20 @@ private function getCallableData($callable, array $options = array())
if ($callable instanceof \Closure) {
$data['type'] = 'closure';

$r = new \ReflectionFunction($callable);
if (false !== strpos($r->name, '{closure}')) {
return $data;
}
$data['name'] = $r->name;

$class = ($class = $r->getClosureThis()) ? \get_class($class) : null;
if ($scopeClass = $r->getClosureScopeClass() ?: $class) {
$data['class'] = $scopeClass;
if (!$class) {
$data['static'] = true;
}
}

return $data;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -354,6 +354,20 @@ protected function describeCallable($callable, array $options = array())
if ($callable instanceof \Closure) {
$string .= "\n- Type: `closure`";

$r = new \ReflectionFunction($callable);
if (false !== strpos($r->name, '{closure}')) {
return $this->write($string."\n");
}
$string .= "\n".sprintf('- Name: `%s`', $r->name);

$class = ($class = $r->getClosureThis()) ? \get_class($class) : null;
if ($scopeClass = $r->getClosureScopeClass() ?: $class) {
$string .= "\n".sprintf('- Class: `%s`', $class);
if (!$class) {
$string .= "\n- Static: yes";
}
}

return $this->write($string."\n");
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -56,12 +56,7 @@ protected function describeRouteCollection(RouteCollection $routes, array $optio

if ($showControllers) {
$controller = $route->getDefault('_controller');
if ($controller instanceof \Closure) {
$controller = 'Closure';
} elseif (\is_object($controller)) {
$controller = \get_class($controller);
}
$row[] = $controller;
$row[] = $this->formatCallable($controller);
}

$tableRows[] = $row;
Expand Down Expand Up @@ -474,7 +469,18 @@ private function formatCallable($callable)
}

if ($callable instanceof \Closure) {
return '\Closure()';
$r = new \ReflectionFunction($callable);
if (false !== strpos($r->name, '{closure}')) {
return 'Closure()';
}
if ($class = $r->getClosureScopeClass()) {
return sprintf('%s::%s()', $class, $r->name);
}
if ($class = $r->getClosureThis()) {
return sprintf('%s::%s()', \get_class($class), $r->name);
}

return $r->name.'()';
}

if (method_exists($callable, '__invoke')) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -580,6 +580,20 @@ private function getCallableDocument($callable)
if ($callable instanceof \Closure) {
$callableXML->setAttribute('type', 'closure');

$r = new \ReflectionFunction($callable);
if (false !== strpos($r->name, '{closure}')) {
return $dom;
}
$callableXML->setAttribute('name', $r->name);

$class = ($class = $r->getClosureThis()) ? \get_class($class) : null;
if ($scopeClass = $r->getClosureScopeClass() ?: $class) {
$callableXML->setAttribute('class', $class);
if (!$class) {
$callableXML->setAttribute('static', 'true');
}
}

return $dom;
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1 +1 @@
\Closure()
Closure()
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,6 @@
 Order   Callable   Priority 
------- ------------------- ----------
#1 global_function() 255
#2 \Closure() -1
#2 Closure() -1
------- ------------------- ----------

Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
 Order   Callable   Priority 
------- ------------------- ----------
#1 global_function() 255
#2 \Closure() -1
#2 Closure() -1
------- ------------------- ----------

"event2" event
Expand Down
13 changes: 11 additions & 2 deletions src/Symfony/Component/EventDispatcher/Debug/WrappedListener.php
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,6 @@ class WrappedListener
public function __construct($listener, $name, Stopwatch $stopwatch, EventDispatcherInterface $dispatcher = null)
{
$this->listener = $listener;
$this->name = $name;
$this->stopwatch = $stopwatch;
$this->dispatcher = $dispatcher;
$this->called = false;
Expand All @@ -44,7 +43,17 @@ public function __construct($listener, $name, Stopwatch $stopwatch, EventDispatc
$this->name = \is_object($listener[0]) ? \get_class($listener[0]) : $listener[0];
$this->pretty = $this->name.'::'.$listener[1];
} elseif ($listener instanceof \Closure) {
$this->pretty = $this->name = 'closure';
$r = new \ReflectionFunction($listener);
if (false !== strpos($r->name, '{closure}')) {
$this->pretty = $this->name = 'closure';
} elseif ($this->name = $r->getClosureScopeClass()) {
$this->pretty = $this->name.'::'.$r->name;
} elseif ($class = $r->getClosureThis()) {
$this->name = \get_class($class);
$this->pretty = $this->name.'::'.$r->name;
} else {
$this->pretty = $this->name = $r->name;
}
} elseif (\is_string($listener)) {
$this->pretty = $this->name = $listener;
} else {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -380,12 +380,27 @@ protected function parseController($controller)
if ($controller instanceof \Closure) {
$r = new \ReflectionFunction($controller);

return array(
$controller = array(
'class' => $r->getName(),
'method' => null,
'file' => $r->getFileName(),
'line' => $r->getStartLine(),
);

if (false !== strpos($r->name, '{closure}')) {
return $controller;
}
$controller['method'] = $r->name;

if ($class = $r->getClosureScopeClass()) {
$controller['class'] = $class;
} elseif ($class = $r->getClosureThis()) {
$controller['class'] = \get_class($class);
} else {
return $r->name;
}

return $controller;
}

if (\is_object($controller)) {
Expand Down
11 changes: 11 additions & 0 deletions src/Symfony/Component/VarDumper/Caster/ReflectionCaster.php
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,17 @@ public static function castClosure(\Closure $c, array $a, Stub $stub, $isNested,
$stub->class = 'Closure'; // HHVM generates unique class names for closures
$a = static::castFunctionAbstract($c, $a, $stub, $isNested, $filter);

if (false === strpos($c->name, '{closure}')) {
if (isset($a[$prefix.'class'])) {
$stub->class = $a[$prefix.'class']->value.'::'.$c->name;
} elseif (isset($a[$prefix.'this'])) {
$stub->class = $a[$prefix.'this']->class.'::'.$c->name;
} else {
$stub->class = $c->name;
}
unset($a[$prefix.'class']);
}

if (isset($a[$prefix.'parameters'])) {
foreach ($a[$prefix.'parameters']->value as &$v) {
$param = $v;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,34 @@ public function testClosureCaster()
);
}

public function testFromCallableClosureCaster()
{
if (\defined('HHVM_VERSION_ID')) {
$this->markTestSkipped('Not for HHVM.');
}
$var = array(
(new \ReflectionMethod($this, __FUNCTION__))->getClosure($this),
(new \ReflectionMethod(__CLASS__, 'tearDownAfterClass'))->getClosure(),
);

$this->assertDumpMatchesFormat(
<<<EOTXT
array:2 [
0 => Symfony\Component\VarDumper\Tests\Caster\ReflectionCasterTest::testFromCallableClosureCaster {
this: Symfony\Component\VarDumper\Tests\Caster\ReflectionCasterTest { …}
file: "%sReflectionCasterTest.php"
line: "%d to %d"
}
1 => %sTestCase::tearDownAfterClass {
file: "%sTestCase.php"
line: "%d to %d"
}
]
EOTXT
, $var
);
}

public function testClosureCasterExcludingVerbosity()
{
$var = function () {};
Expand Down

0 comments on commit 41eaba5

Please sign in to comment.