8000 [Console] Bind the closure (code) to the Command if possible · symfony/symfony@256de36 · GitHub
[go: up one dir, main page]

Skip to content

Commit 256de36

Browse files
committed
[Console] Bind the closure (code) to the Command if possible
1 parent 862bdf1 commit 256de36

File tree

2 files changed

+45
-0
lines changed

2 files changed

+45
-0
lines changed

src/Symfony/Component/Console/Command/Command.php

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -284,6 +284,13 @@ public function setCode($code)
284284
throw new \InvalidArgumentException('Invalid callable provided to Command::setCode.');
285285
}
286286

287+
if (PHP_VERSION_ID >= 50400 && $code instanceof \Closure) {
288+
$r = new \ReflectionFunction($code);
289+
if (null === $r->getClosureThis()) {
290+
$code = \Closure::bind($code, $this);
291+
}
292+
}
293+
287294
$this->code = $code;
288295

289296
return $this;

src/Symfony/Component/Console/Tests/Command/CommandTest.php

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -293,6 +293,33 @@ public function testSetCode()
293293
$this->assertEquals('interact called'.PHP_EOL.'from the code...'.PHP_EOL, $tester->getDisplay());
294294
}
295295

296+
public function getSetCodeBindToClosureTests()
297+
{
298+
return array(
299+
array(true, 'not binded'),
300+
array(false, 'binded'),
301+
);
302+
}
303+
304+
/** @dataProvider getSetCodeBindToClosureTests */
305+
public function testSetCodeBindToClosure($previouslyBinded, $expected)
306+
{
307+
if (PHP_VERSION_ID < 50400) {
308+
$this->markTestSkipped('Test skipped, for PHP 5.4+ only.');
309+
}
310+
311+
$code = create_closure();
312+
if ($previouslyBinded) {
313+
$code = $code->bindTo($this);
314+
}
315+
316+
$command = new \TestCommand();
317+
$command->setCode($code);
318+
$tester = new CommandTester($command);
319+
$tester->execute(array());
320+
$this->assertEquals('interact called'.PHP_EOL.$expected.PHP_EOL, $tester->getDisplay());
321+
}
322+
296323
public function testSetCodeWithNonClosureCallable()
297324
{
298325
$command = new \TestCommand();
@@ -346,3 +373,14 @@ public function testLegacyAsXml()
346373
$this->assertXmlStringEqualsXmlFile(self::$fixturesPath.'/command_asxml.txt', $command->asXml(), '->asXml() returns an XML representation of the command');
347374
}
348375
}
376+
377+
// In order to get an unbinded closure, we should create it outside a class
378+
// scope It's not possible to unbind a closure (At least on PHP 5.6.7) even if
379+
// the PHP documentation says it's possible.
380+
function create_closure()
381+
{
382+
return function(InputInterface $input, OutputInterface $output)
383+
{
384+
$output->writeln($this instanceof Command ? 'binded' : 'not binded');
385+
};
386+
}

0 commit comments

Comments
 (0)
0