8000 feature #14431 [Console] Bind the closure (code) to the Command if po… · symfony/symfony@e861134 · GitHub
[go: up one dir, main page]

Skip to content

Commit e861134

Browse files
committed
feature #14431 [Console] Bind the closure (code) to the Command if possible (lyrixx)
This PR was merged into the 2.8 branch. Discussion ---------- [Console] Bind the closure (code) to the Command if possible | Q | A | ------------- | --- | Bug fix? | no | New feature? | yes | BC breaks? | no | Deprecations? | no | Tests pass? | yes | Fixed tickets | ~ | License | MIT | Doc PR | ~ This allow this kind of code: ```php #!/usr/bin/env php <?php require __DIR__.'/vendor/autoload.php'; use Symfony\Component\Console\Application; use Symfony\Component\Console\Command\Command; use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Output\OutputInterface; $application = new Application(); $application->add((new Command('process'))) ->setDescription('Play all other commands') ->setCode(function (InputInterface $input, OutputInterface $output) use ($application) { $application = $this->getApplication(); $help = $application->find('help'); $output->writeln($help->getHelp()); }) ; $application->run(); ``` Commits ------- ff4424a [Console] Bind the closure (code) to the Command if possible
2 parents 449b18c + ff4424a commit e861134

File tree

2 files changed

+44
-0
lines changed

2 files changed

+44
-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: 37 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 bound to the command'),
300+
array(false, 'bound to the command'),
301+
);
302+
}
303+
304+
/** @dataProvider getSetCodeBindToClosureTests */
305+
public function testSetCodeBindToClosure($previouslyBound, $expected)
306+
{
307+
if (PHP_VERSION_ID < 50400) {
308+
$this->markTestSkipped('Test skipped, for PHP 5.4+ only.');
309+
}
310+
311+
$code = createClosure();
312+
if ($previouslyBound) {
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,13 @@ 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 unbound closure, we should create it outside a class
378+
// scope.
379+
function createClosure()
380+
{
381+
return function(InputInterface $input, OutputInterface $output)
382+
{
383+
$output->writeln($this instanceof Command ? 'bound to the command' : 'not bound to the command');
384+
};
385+
}

0 commit comments

Comments
 (0)
0