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)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy