Skip to content

Commit cae216d

Browse files
authored
Added as command for static method (#6978)
1 parent 6c5cc3e commit cae216d

4 files changed

Lines changed: 72 additions & 5 deletions

File tree

src/AsCommand.php

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,9 @@
1212

1313
namespace Hyperf\Command;
1414

15+
use Closure;
1516
use Hyperf\Command\Concerns\InteractsWithIO;
17+
use Hyperf\Di\ReflectionManager;
1618
use Hyperf\Stringable\Str;
1719
use Psr\Container\ContainerInterface;
1820

@@ -56,6 +58,12 @@ public function handle()
5658
{
5759
$inputs = array_merge($this->input->getArguments(), $this->input->getOptions());
5860
$parameters = $this->parameterParser->parseMethodParameters($this->class, $this->method, $inputs);
61+
62+
if (ReflectionManager::reflectMethod($this->class, $this->method)->isStatic()) {
63+
Closure::bind(fn ($method) => self::{$method}(...$parameters), null, $this->class)($this->method);
64+
return;
65+
}
66+
5967
$instance = $this->container->get($this->class);
6068

6169
if (in_array(InteractsWithIO::class, class_uses_recursive($this->class))) {

src/ClosureCommand.php

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
use Hyperf\Crontab\Schedule;
1818
use Hyperf\Stringable\Str;
1919
use Psr\Container\ContainerInterface;
20+
use ReflectionFunction;
2021

2122
use function Hyperf\Tappable\tap;
2223

@@ -57,6 +58,12 @@ public function handle()
5758
{
5859
$inputs = array_merge($this->input->getArguments(), $this->input->getOptions());
5960
$parameters = $this->parameterParser->parseClosureParameters($this->closure, $inputs);
61+
$ref = new ReflectionFunction($this->closure);
62+
63+
if ($ref->isStatic()) {
64+
($this->closure)(...$parameters);
65+
return;
66+
}
6067

6168
$this->closure->call($this, ...$parameters);
6269
}

tests/AsCommandAndClosureCommandTest.php

Lines changed: 50 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,9 @@
3737
use Mockery;
3838
use PHPUnit\Framework\Attributes\CoversNothing;
3939
use PHPUnit\Framework\TestCase;
40+
use RuntimeException;
41+
use Symfony\Component\Console\Input\ArrayInput;
42+
use Symfony\Component\Console\Output\BufferedOutput;
4043

4144
/**
4245
* @internal
@@ -84,7 +87,7 @@ public function testRegisterAsCommand()
8487
);
8588

8689
$commands = array_values($this->containerSet);
87-
$this->assertCount(3, $commands);
90+
$this->assertCount(4, $commands);
8891

8992
$runCommand = $commands[0];
9093
$runCommandDefinition = $runCommand->getDefinition();
@@ -110,37 +113,79 @@ public function testRegisterAsCommand()
110113
$this->assertNotNull($runWithoutOptionsCommandDefinition->getOption('name'));
111114
$this->assertNotNull($runWithoutOptionsCommandDefinition->getOption('age'));
112115
$this->assertNotNull($runWithoutOptionsCommandDefinition->getOption('testBool'));
116+
117+
$runStaticCommand = $commands[3];
118+
$runStaticCommand->setInput(new ArrayInput([]));
119+
$runStaticCommand->setOutput(new BufferedOutput());
120+
$runStaticCommandDefinition = $runStaticCommand->getDefinition();
121+
$this->assertEquals($this->getSignature($runStaticCommand), 'command:as-command:runStatic');
122+
$this->assertEquals(count($runStaticCommandDefinition->getOptions()), 1);
123+
$this->assertEquals(count($runStaticCommandDefinition->getArguments()), 0);
124+
// assert runtime exception
125+
try {
126+
$runStaticCommand->handle();
127+
} catch (RuntimeException $e) {
128+
$this->assertEquals('command:as-command:runStatic', $e->getMessage());
129+
}
113130
}
114131

115132
public function testRegisterClosureCommand()
116133
{
117134
$runCommand = Console::command('command:closure:run', function () {
118-
return 'closure';
135+
throw new RuntimeException('command:closure:run');
119136
});
137+
$runCommand->setInput(new ArrayInput([]));
138+
$runCommand->setOutput(new BufferedOutput());
120139
$runCommandDefinition = $runCommand->getDefinition();
121140
$this->assertEquals($this->getSignature($runCommand), 'command:closure:run');
122141
$this->assertEquals(count($runCommandDefinition->getOptions()), 1);
123142
$this->assertEquals(count($runCommandDefinition->getArguments()), 0);
124143
$this->assertNotNull($runCommandDefinition->getOption('disable-event-dispatcher'));
144+
$this->expectException(RuntimeException::class);
145+
$this->expectExceptionMessage('command:closure:run');
146+
$runCommand->handle();
147+
}
125148

149+
public function testRegisterStaticClosureCommand()
150+
{
151+
$runCommand = Console::command('command:closure:run-static', static function () {
152+
throw new RuntimeException('command:closure:run-static');
153+
});
154+
$runCommand->setInput(new ArrayInput([]));
155+
$runCommand->setOutput(new BufferedOutput());
156+
$runCommandDefinition = $runCommand->getDefinition();
157+
$this->assertEquals($this->getSignature($runCommand), 'command:closure:run-static');
158+
$this->assertEquals(count($runCommandDefinition->getOptions()), 1);
159+
$this->assertEquals(count($runCommandDefinition->getArguments()), 0);
160+
$this->assertNotNull($runCommandDefinition->getOption('disable-event-dispatcher'));
161+
$this->expectException(RuntimeException::class);
162+
$this->expectExceptionMessage('command:closure:run-static');
163+
$runCommand->handle();
164+
}
165+
166+
public function testRegisterClosureCommandWithDefineOptions()
167+
{
126168
$runWithDefinedOptionsCommand = Console::command('command:closure:withDefineOptions {--name=}', function (string $name) {
127-
return 'with define options';
169+
return $name;
128170
});
129171
$runWithDefinedOptionsCommandDefinition = $runWithDefinedOptionsCommand->getDefinition();
130172
$this->assertEquals($this->getSignature($runWithDefinedOptionsCommand), 'command:closure:withDefineOptions {--name=}');
131173
$this->assertEquals(count($runWithDefinedOptionsCommandDefinition->getOptions()), 2);
132174
$this->assertEquals(count($runWithDefinedOptionsCommandDefinition->getArguments()), 0);
133-
$this->assertNotNull($runCommandDefinition->getOption('disable-event-dispatcher'));
175+
$this->assertNotNull($runWithDefinedOptionsCommandDefinition->getOption('disable-event-dispatcher'));
134176
$this->assertNotNull($runWithDefinedOptionsCommandDefinition->getOption('name'));
177+
}
135178

179+
public function testRegisterClosureCommandWithoutDefineOptions()
180+
{
136181
$runWithoutOptionsCommand = Console::command('command:closure:withoutDefineOptions', function (string $name, int $age = 9, bool $testBool = false) {
137182
return 'with define options';
138183
});
139184
$runWithoutOptionsCommandDefinition = $runWithoutOptionsCommand->getDefinition();
140185
$this->assertEquals($this->getSignature($runWithoutOptionsCommand), 'command:closure:withoutDefineOptions');
141186
$this->assertEquals(count($runWithoutOptionsCommandDefinition->getOptions()), 4);
142187
$this->assertEquals(count($runWithoutOptionsCommandDefinition->getArguments()), 0);
143-
$this->assertNotNull($runCommandDefinition->getOption('disable-event-dispatcher'));
188+
$this->assertNotNull($runWithoutOptionsCommandDefinition->getOption('disable-event-dispatcher'));
144189
$this->assertNotNull($runWithoutOptionsCommandDefinition->getOption('name'));
145190
$this->assertNotNull($runWithoutOptionsCommandDefinition->getOption('age'));
146191
$this->assertNotNull($runWithoutOptionsCommandDefinition->getOption('testBool'));

tests/Command/Annotation/TestAsCommand.php

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
namespace HyperfTest\Command\Command\Annotation;
1414

1515
use Hyperf\Command\Annotation\AsCommand;
16+
use RuntimeException;
1617

1718
class TestAsCommand
1819
{
@@ -33,4 +34,10 @@ public function runWithoutOptions(string $name, int $age = 9, bool $testBool = f
3334
{
3435
return 'runWithoutOptions';
3536
}
37+
38+
#[AsCommand('command:as-command:runStatic')]
39+
protected static function runStatic()
40+
{
41+
throw new RuntimeException('command:as-command:runStatic');
42+
}
3643
}

0 commit comments

Comments
 (0)