Skip to content

Commit

Permalink
[Console] Bind the closure (code) to the Command if possible
Browse files Browse the repository at this point in the history
  • Loading branch information
lyrixx committed Apr 22, 2015
1 parent 862bdf1 commit ff4424a
Show file tree
Hide file tree
Showing 2 changed files with 44 additions and 0 deletions.
7 changes: 7 additions & 0 deletions src/Symfony/Component/Console/Command/Command.php
Expand Up @@ -284,6 +284,13 @@ public function setCode($code)
throw new \InvalidArgumentException('Invalid callable provided to Command::setCode.');
}

if (PHP_VERSION_ID >= 50400 && $code instanceof \Closure) {
$r = new \ReflectionFunction($code);
if (null === $r->getClosureThis()) {
$code = \Closure::bind($code, $this);
}
}

$this->code = $code;

return $this;
Expand Down
37 changes: 37 additions & 0 deletions src/Symfony/Component/Console/Tests/Command/CommandTest.php
Expand Up @@ -293,6 +293,33 @@ public function testSetCode()
$this->assertEquals('interact called'.PHP_EOL.'from the code...'.PHP_EOL, $tester->getDisplay());
}

public function getSetCodeBindToClosureTests()
{
return array(
array(true, 'not bound to the command'),
array(false, 'bound to the command'),
);
}

/** @dataProvider getSetCodeBindToClosureTests */
public function testSetCodeBindToClosure($previouslyBound, $expected)
{
if (PHP_VERSION_ID < 50400) {
$this->markTestSkipped('Test skipped, for PHP 5.4+ only.');
}

$code = createClosure();
if ($previouslyBound) {
$code = $code->bindTo($this);
}

$command = new \TestCommand();
$command->setCode($code);
$tester = new CommandTester($command);
$tester->execute(array());
$this->assertEquals('interact called'.PHP_EOL.$expected.PHP_EOL, $tester->getDisplay());
}

public function testSetCodeWithNonClosureCallable()
{
$command = new \TestCommand();
Expand Down Expand Up @@ -346,3 +373,13 @@ public function testLegacyAsXml()
$this->assertXmlStringEqualsXmlFile(self::$fixturesPath.'/command_asxml.txt', $command->asXml(), '->asXml() returns an XML representation of the command');
}
}

// In order to get an unbound closure, we should create it outside a class
// scope.
function createClosure()
{
return function(InputInterface $input, OutputInterface $output)
{
$output->writeln($this instanceof Command ? 'bound to the command' : 'not bound to the command');
};
}

0 comments on commit ff4424a

Please sign in to comment.