33namespace FrameworkX ;
44
55use FrameworkX \Io \FiberHandler ;
6+ use FrameworkX \Io \LogStreamHandler ;
67use FrameworkX \Io \MiddlewareHandler ;
78use FrameworkX \Io \RedirectHandler ;
89use FrameworkX \Io \RouteHandler ;
@@ -24,9 +25,12 @@ class App
2425 /** @var RouteHandler */
2526 private $ router ;
2627
27- /** @var SapiHandler */
28+ /** @var ? SapiHandler */
2829 private $ sapi ;
2930
31+ /** @var ?LogStreamHandler */
32+ private $ logger ;
33+
3034 /** @var Container */
3135 private $ container ;
3236
@@ -115,7 +119,8 @@ public function __construct(...$middleware)
115119 $ this ->router = new RouteHandler ($ this ->container );
116120 $ handlers [] = $ this ->router ;
117121 $ this ->handler = new MiddlewareHandler ($ handlers );
118- $ this ->sapi = new SapiHandler ();
122+ $ this ->sapi = (\PHP_SAPI !== 'cli ' ? new SapiHandler () : null );
123+ $ this ->logger = (\PHP_SAPI === 'cli ' ? new LogStreamHandler ('php://output ' ) : null );
119124 }
120125
121126 /**
@@ -231,6 +236,9 @@ public function run(): void
231236
232237 private function runLoop (): void
233238 {
239+ $ logger = $ this ->logger ;
240+ assert ($ logger instanceof LogStreamHandler);
241+
234242 $ http = new HttpServer (function (ServerRequestInterface $ request ) {
235243 return $ this ->handleRequest ($ request );
236244 });
@@ -240,31 +248,31 @@ private function runLoop(): void
240248 $ socket = new SocketServer ($ listen );
241249 $ http ->listen ($ socket );
242250
243- $ this -> sapi ->log ('Listening on ' . \str_replace ('tcp: ' , 'http: ' , (string ) $ socket ->getAddress ()));
251+ $ logger ->log ('Listening on ' . \str_replace ('tcp: ' , 'http: ' , (string ) $ socket ->getAddress ()));
244252
245- $ http ->on ('error ' , function (\Exception $ e ): void {
246- $ this -> sapi ->log ('HTTP error: ' . $ e ->getMessage ());
253+ $ http ->on ('error ' , static function (\Exception $ e) use ( $ logger ): void {
254+ $ logger ->log ('HTTP error: ' . $ e ->getMessage ());
247255 });
248256
249257 // @codeCoverageIgnoreStart
250258 try {
251- Loop::addSignal (\defined ('SIGINT ' ) ? \SIGINT : 2 , $ f1 = function () use ($ socket ) {
259+ Loop::addSignal (\defined ('SIGINT ' ) ? \SIGINT : 2 , $ f1 = static function () use ($ socket, $ logger ) {
252260 if (\PHP_VERSION_ID >= 70200 && \stream_isatty (\STDIN )) {
253261 echo "\r" ;
254262 }
255- $ this -> sapi ->log ('Received SIGINT, stopping loop ' );
263+ $ logger ->log ('Received SIGINT, stopping loop ' );
256264
257265 $ socket ->close ();
258266 Loop::stop ();
259267 });
260- Loop::addSignal (\defined ('SIGTERM ' ) ? \SIGTERM : 15 , $ f2 = function () use ($ socket ) {
261- $ this -> sapi ->log ('Received SIGTERM, stopping loop ' );
268+ Loop::addSignal (\defined ('SIGTERM ' ) ? \SIGTERM : 15 , $ f2 = static function () use ($ socket, $ logger ) {
269+ $ logger ->log ('Received SIGTERM, stopping loop ' );
262270
263271 $ socket ->close ();
264272 Loop::stop ();
265273 });
266274 } catch (\BadMethodCallException $ e ) {
267- $ this -> sapi ->log ('Notice: No signal handler support, installing ext-ev or ext-pcntl recommended for production use. ' );
275+ $ logger ->log ('Notice: No signal handler support, installing ext-ev or ext-pcntl recommended for production use. ' );
268276 }
269277 // @codeCoverageIgnoreEnd
270278
@@ -273,7 +281,7 @@ private function runLoop(): void
273281
274282 if ($ socket ->getAddress () !== null ) {
275283 // Fiber compatibility mode for PHP < 8.1: Restart loop as long as socket is available
276- $ this -> sapi ->log ('Warning: Loop restarted. Upgrade to react/async v4 recommended for production use. ' );
284+ $ logger ->log ('Warning: Loop restarted. Upgrade to react/async v4 recommended for production use. ' );
277285 } else {
278286 break ;
279287 }
@@ -286,6 +294,7 @@ private function runLoop(): void
286294
287295 private function runOnce (): void
288296 {
297+ assert ($ this ->sapi instanceof SapiHandler);
289298 $ request = $ this ->sapi ->requestFromGlobals ();
290299
291300 $ response = $ this ->handleRequest ($ request );
@@ -294,6 +303,7 @@ private function runOnce(): void
294303 $ this ->sapi ->sendResponse ($ response );
295304 } elseif ($ response instanceof PromiseInterface) {
296305 $ response ->then (function (ResponseInterface $ response ) {
306+ assert ($ this ->sapi instanceof SapiHandler);
297307 $ this ->sapi ->sendResponse ($ response );
298308 });
299309 }
0 commit comments