Skip to content

Commit f625681

Browse files
committed
Update runner API to use invokable classes instead of a run() method
1 parent 43853d0 commit f625681

File tree

6 files changed

+62
-36
lines changed

6 files changed

+62
-36
lines changed

src/App.php

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -251,14 +251,14 @@ public function redirect(string $route, string $target, int $code = Response::ST
251251
* When executed behind traditional PHP SAPIs (PHP-FPM, FastCGI, Apache, etc.),
252252
* this will handle a single request and run until a single response is sent.
253253
* This is particularly useful because it allows you to run the exact same
254-
* app in any environment.
254+
* application code in any environment.
255255
*
256-
* @see HttpServerRunner::run()
257-
* @see SapiRunner::run()
256+
* @see HttpServerRunner::__invoke()
257+
* @see SapiRunner::__invoke()
258258
*/
259259
public function run(): void
260260
{
261-
$this->runner->run(\Closure::fromCallable([$this, 'handleRequest']));
261+
($this->runner)(\Closure::fromCallable([$this, 'handleRequest']));
262262
}
263263

264264
/**

src/Runner/HttpServerRunner.php

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,11 @@ public function __construct(LogStreamHandler $logger, ?string $listenAddress)
3838
$this->listenAddress = $listenAddress ?? '127.0.0.1:8080';
3939
}
4040

41-
public function run(callable $handler): void
41+
/**
42+
* @param callable(\Psr\Http\Message\ServerRequestInterface):(\Psr\Http\Message\ResponseInterface|\React\Promise\PromiseInterface<\Psr\Http\Message\ResponseInterface>) $handler
43+
* @return void
44+
*/
45+
public function __invoke(callable $handler): void
4246
{
4347
$socket = new SocketServer($this->listenAddress);
4448

src/Runner/SapiRunner.php

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,10 +13,10 @@
1313
/**
1414
* [Internal] Application runner for traditional PHP SAPIs.
1515
*
16-
* This request runner will be used when executed behind traditional PHP SAPIs
16+
* This application runner will be used when executed behind traditional PHP SAPIs
1717
* (PHP-FPM, FastCGI, Apache, etc.). It will handle a single request and run
1818
* until a single response is sent. This is particularly useful because it
19-
* allows you to run the exact same app in any environment.
19+
* allows you to run the exact same application code in any environment.
2020
*
2121
* Note that this is an internal class only and nothing you should usually have
2222
* to care about. See also the `App` and `HttpServerRunner` for more details.
@@ -25,7 +25,11 @@
2525
*/
2626
class SapiRunner
2727
{
28-
public function run(callable $handler): void
28+
/**
29+
* @param callable(ServerRequestInterface):(ResponseInterface|PromiseInterface<ResponseInterface>) $handler
30+
* @return void
31+
*/
32+
public function __invoke(callable $handler): void
2933
{
3034
$request = $this->requestFromGlobals();
3135

tests/AppTest.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -919,10 +919,10 @@ public function testConstructWithContainerWithListenAddressWillPassListenAddress
919919
$this->assertEquals('0.0.0.0:8081', $listenAddress);
920920
}
921921

922-
public function testRunWillExecuteRunOnRunnerFromContainer(): void
922+
public function testRunWillInvokeRunnerFromContainer(): void
923923
{
924924
$runner = $this->createMock(HttpServerRunner::class);
925-
$runner->expects($this->once())->method('run');
925+
$runner->expects($this->once())->method('__invoke');
926926

927927
$container = new Container([
928928
HttpServerRunner::class => $runner

tests/Runner/HttpServerRunnerTest.php

Lines changed: 40 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414

1515
class HttpServerRunnerTest extends TestCase
1616
{
17-
public function testRunWillReportDefaultListeningAddressAndRunLoop(): void
17+
public function testInvokeWillReportDefaultListeningAddressAndRunLoop(): void
1818
{
1919
$socket = @stream_socket_server('127.0.0.1:8080');
2020
if ($socket === false) {
@@ -41,10 +41,12 @@ public function testRunWillReportDefaultListeningAddressAndRunLoop(): void
4141
Loop::stop();
4242
});
4343

44-
$runner->run(function (): void { });
44+
$runner(function (): void {
45+
throw new \BadFunctionCallException('Should not be reached');
46+
});
4547
}
4648

47-
public function testRunWillReportGivenListeningAddressAndRunLoop(): void
49+
public function testInvokeWillReportGivenListeningAddressAndRunLoop(): void
4850
{
4951
$socket = stream_socket_server('127.0.0.1:0');
5052
assert(is_resource($socket));
@@ -70,10 +72,12 @@ public function testRunWillReportGivenListeningAddressAndRunLoop(): void
7072
Loop::stop();
7173
});
7274

73-
$runner->run(function (): void { });
75+
$runner(function (): void {
76+
throw new \BadFunctionCallException('Should not be reached');
77+
});
7478
}
7579

76-
public function testRunWillReportGivenListeningAddressWithRandomPortAndRunLoop(): void
80+
public function testInvokeWillReportGivenListeningAddressWithRandomPortAndRunLoop(): void
7781
{
7882
$logger = $this->createMock(LogStreamHandler::class);
7983
$logger->expects($this->atLeastOnce())->method('log')->withConsecutive([$this->matches('Listening on http://127.0.0.1:%d')]);
@@ -93,10 +97,12 @@ public function testRunWillReportGivenListeningAddressWithRandomPortAndRunLoop()
9397
Loop::stop();
9498
});
9599

96-
$runner->run(function (): void { });
100+
$runner(function (): void {
101+
throw new \BadFunctionCallException('Should not be reached');
102+
});
97103
}
98104

99-
public function testRunWillRestartLoopUntilSocketIsClosed(): void
105+
public function testInvokeWillRestartLoopUntilSocketIsClosed(): void
100106
{
101107
$logger = $this->createMock(LogStreamHandler::class);
102108
assert($logger instanceof LogStreamHandler);
@@ -120,10 +126,12 @@ public function testRunWillRestartLoopUntilSocketIsClosed(): void
120126
Loop::stop();
121127
});
122128

123-
$runner->run(function (): void { });
129+
$runner(function (): void {
130+
throw new \BadFunctionCallException('Should not be reached');
131+
});
124132
}
125133

126-
public function testRunWillListenForHttpRequestAndSendBackHttpResponseOverSocket(): void
134+
public function testInvokeWillListenForHttpRequestAndSendBackHttpResponseOverSocket(): void
127135
{
128136
$socket = stream_socket_server('127.0.0.1:0');
129137
assert(is_resource($socket));
@@ -163,12 +171,12 @@ public function testRunWillListenForHttpRequestAndSendBackHttpResponseOverSocket
163171
});
164172
});
165173

166-
$runner->run(function (): Response {
174+
$runner(function (): Response {
167175
return new Response(200, ['Date' => '', 'Server' => ''], "OK\n");
168176
});
169177
}
170178

171-
public function testRunWillOnlyRestartLoopAfterAwaitingWhenFibersAreNotAvailable(): void
179+
public function testInvokeWillOnlyRestartLoopAfterAwaitingWhenFibersAreNotAvailable(): void
172180
{
173181
$socket = stream_socket_server('127.0.0.1:0');
174182
assert(is_resource($socket));
@@ -216,7 +224,7 @@ public function testRunWillOnlyRestartLoopAfterAwaitingWhenFibersAreNotAvailable
216224
});
217225

218226
$done = false;
219-
$runner->run(function () use (&$done): Response {
227+
$runner(function () use (&$done): Response {
220228
$promise = new Promise(function (callable $resolve) use (&$done): void {
221229
Loop::futureTick(function () use ($resolve, &$done): void {
222230
$resolve(null);
@@ -232,7 +240,7 @@ public function testRunWillOnlyRestartLoopAfterAwaitingWhenFibersAreNotAvailable
232240
$this->assertTrue($done);
233241
}
234242

235-
public function testRunWillReportHttpErrorForInvalidClientRequest(): void
243+
public function testInvokeWillReportHttpErrorForInvalidClientRequest(): void
236244
{
237245
$socket = stream_socket_server('127.0.0.1:0');
238246
assert(is_resource($socket));
@@ -269,14 +277,16 @@ public function testRunWillReportHttpErrorForInvalidClientRequest(): void
269277
});
270278
});
271279

272-
$runner->run(function (): void { });
280+
$runner(function (): void {
281+
throw new \BadFunctionCallException('Should not be reached');
282+
});
273283
}
274284

275285
/**
276286
* @requires function pcntl_signal
277287
* @requires function posix_kill
278288
*/
279-
public function testRunWillStopWhenReceivingSigint(): void
289+
public function testInvokeWillStopWhenReceivingSigint(): void
280290
{
281291
$logger = $this->createMock(LogStreamHandler::class);
282292
$logger->expects($this->exactly(2))->method('log');
@@ -293,14 +303,16 @@ public function testRunWillStopWhenReceivingSigint(): void
293303
});
294304

295305
$this->expectOutputRegex("#^\r?$#");
296-
$runner->run(function (): void { });
306+
$runner(function (): void {
307+
throw new \BadFunctionCallException('Should not be reached');
308+
});
297309
}
298310

299311
/**
300312
* @requires function pcntl_signal
301313
* @requires function posix_kill
302314
*/
303-
public function testRunWillStopWhenReceivingSigterm(): void
315+
public function testInvokeWillStopWhenReceivingSigterm(): void
304316
{
305317
$logger = $this->createMock(LogStreamHandler::class);
306318
assert($logger instanceof LogStreamHandler);
@@ -315,21 +327,25 @@ public function testRunWillStopWhenReceivingSigterm(): void
315327
posix_kill($pid, defined('SIGTERM') ? SIGTERM : 15);
316328
});
317329

318-
$runner->run(function (): void { });
330+
$runner(function (): void {
331+
throw new \BadFunctionCallException('Should not be reached');
332+
});
319333
}
320334

321-
public function testRunWithEmptyAddressThrows(): void
335+
public function testInvokeWithEmptyAddressThrows(): void
322336
{
323337
$logger = $this->createMock(LogStreamHandler::class);
324338
assert($logger instanceof LogStreamHandler);
325339

326340
$runner = new HttpServerRunner($logger, '');
327341

328342
$this->expectException(\InvalidArgumentException::class);
329-
$runner->run(function (): void { });
343+
$runner(function (): void {
344+
throw new \BadFunctionCallException('Should not be reached');
345+
});
330346
}
331347

332-
public function testRunWithBusyPortThrows(): void
348+
public function testInvokeWithBusyPortThrows(): void
333349
{
334350
$socket = stream_socket_server('127.0.0.1:0');
335351
assert(is_resource($socket));
@@ -347,6 +363,8 @@ public function testRunWithBusyPortThrows(): void
347363

348364
$this->expectException(\RuntimeException::class);
349365
$this->expectExceptionMessage('Failed to listen on');
350-
$runner->run(function (): void { });
366+
$runner(function (): void {
367+
throw new \BadFunctionCallException('Should not be reached');
368+
});
351369
}
352370
}

tests/Runner/SapiRunnerTest.php

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -480,15 +480,15 @@ public function testSendResponseSetsMultipleCookieHeaders(): void
480480
/**
481481
* @runInSeparateProcess
482482
*/
483-
public function testRunWillSendResponseHeadersFromHandler(): void
483+
public function testInvokeWillSendResponseHeadersFromHandler(): void
484484
{
485485
$sapi = new SapiRunner();
486486

487487
header_remove();
488488
$_SERVER['SERVER_PROTOCOL'] = 'http/1.1';
489489

490490
$this->expectOutputString('');
491-
$sapi->run(function () {
491+
$sapi(function () {
492492
return new Response();
493493
});
494494

@@ -502,15 +502,15 @@ public function testRunWillSendResponseHeadersFromHandler(): void
502502
/**
503503
* @runInSeparateProcess
504504
*/
505-
public function testRunWillSendResponseHeadersFromDeferredHandler(): void
505+
public function testInvokeWillSendResponseHeadersFromDeferredHandler(): void
506506
{
507507
$sapi = new SapiRunner();
508508

509509
header_remove();
510510
$_SERVER['SERVER_PROTOCOL'] = 'http/1.1';
511511

512512
$this->expectOutputString('');
513-
$sapi->run(function () {
513+
$sapi(function () {
514514
return resolve(new Response());
515515
});
516516

0 commit comments

Comments
 (0)