@@ -84,47 +84,55 @@ public function __construct(
8484 }
8585
8686 /**
87- * Logs an error message with details about the exception.
88- *
89- * @param Exception $e The exception to log.
90- * @param bool $fatal Optional. Indicates whether the error is fatal. Defaults to false.
91- * If true, the server will stop after logging the error.
87+ * Initializes the server by creating a stream socket server and setting it to non-blocking mode.
9288 *
93- * @return string
89+ * @throws Exception If the server fails to be created.
9490 */
95- public function logError ( $ e , bool $ fatal = false ): void
91+ public function init (? LoopInterface $ loop = null , bool $ stream_socket_server = false ): void
9692 {
97- if ($ fatal ) $ this ->close () ;
98- $ error = ' Error: ' . $ e -> getMessage () . PHP_EOL .
99- ' Line ' . $ e -> getLine () . ' in ' . $ e -> getFile () . PHP_EOL .
100- $ e -> getTraceAsString ();
101- if ( isset ( $ this -> logger )) $ this ->logger -> warning ( $ error );
93+ if ($ this ->running ) return ;
94+ $ this -> initialized = true ;
95+ ( $ stream_socket_server )
96+ ? $ this -> initStreamSocketServer ()
97+ : $ this ->initReactHttpServer ( $ loop );
10298 }
10399
104100 /**
105- * Initializes the server by creating a stream socket server and setting it to non-blocking mode .
101+ * Initializes a stream socket server.
106102 *
107- * @throws Exception If the server fails to be created.
103+ * This method creates a stream socket server using the specified host address.
104+ * If the server cannot be created, an exception is thrown with the error details.
105+ *
106+ * @throws Exception If the stream socket server fails to initialize.
108107 */
109- public function init (? LoopInterface $ loop = null , bool $ stream_socket_server = false ): void
108+ private function initStreamSocketServer ( ): void
110109 {
111- if ($ this ->running ) return ;
112- if ($ stream_socket_server ) {
113- $ this ->server = stream_socket_server ("{$ this ->hostAddr }" , $ errno , $ errstr );
114- if (! is_resource ($ this ->server )) {
115- throw new Exception ("Failed to create server: $ errstr ( $ errno) " );
116- }
117- } else {
118- $ this ->server = new HttpServer (
119- $ this ->loop = $ loop instanceof LoopInterface
120- ? $ loop
121- : Loop::get (),
122- fn ($ request ) => $ this ->handleReact ($ request )
123- );
124- $ this ->server ->on ('error ' , fn (Throwable $ e ) => $ this ->logError ($ e , true ));
125- $ this ->socket = new SocketServer ($ this ->hostAddr , [], $ this ->loop );
110+ if (! is_resource ($ this ->server = stream_socket_server ("{$ this ->hostAddr }" , $ errno , $ errstr ))) {
111+ throw new Exception ("Failed to create server: $ errstr ( $ errno) " );
126112 }
127- $ this ->initialized = true ;
113+ }
114+
115+ /**
116+ * Initializes the ReactPHP HTTP server.
117+ *
118+ * This method sets up an HTTP server using ReactPHP's HttpServer and SocketServer.
119+ * It accepts an optional event loop instance. If no loop is provided, it defaults
120+ * to using the global loop instance. The HTTP server is configured to handle incoming
121+ * requests via the `handleReact` method and logs errors using the `logError` method.
122+ *
123+ * @param LoopInterface|null $loop Optional event loop instance. If null, the global loop is used.
124+ *
125+ * @return void
126+ */
127+ private function initReactHttpServer (?LoopInterface $ loop = null ): void
128+ {
129+ $ this ->server = new HttpServer (
130+ $ this ->loop = $ loop instanceof LoopInterface
131+ ? $ loop
132+ : Loop::get (),
133+ fn ($ request ) => $ this ->handleReact ($ request )
134+ )->on ('error ' , fn (Throwable $ e ) => $ this ->logError ($ e , true ));
135+ $ this ->socket = new SocketServer ($ this ->hostAddr , [], $ this ->loop );
128136 }
129137
130138 /**
@@ -138,21 +146,48 @@ public function start(bool $start_loop = false): void
138146 $ this ->init ();
139147 }
140148 if (! $ this ->running ) {
141- if ($ this ->server instanceof HttpServer) {
142- $ this ->server ->listen ($ this ->socket );
143- $ this ->running = true ;
144- if ($ start_loop ) $ this ->loop ->run ();
145- } elseif (is_resource ($ this ->server )) {
146- $ this ->running = true ;
147- while ($ this ->running ) {
148- if (stripos (PHP_OS , 'WIN ' ) === false && extension_loaded ('pcntl ' )) {
149- pcntl_signal_dispatch ();
150- }
151- if ($ client = @stream_socket_accept ($ this ->server , 0 )) {
152- $ this ->handleResource ($ client );
153- }
154- }
149+ $ this ->running = true ;
150+ ($ this ->server instanceof HttpServer)
151+ ? $ this ->startReact ($ start_loop )
152+ : $ this ->startResource ();
153+ }
154+ }
155+
156+ /**
157+ * Starts the ReactPHP server by binding it to the specified socket.
158+ *
159+ * @param bool $start_loop Determines whether to start the event loop.
160+ * - If true, the event loop will be started.
161+ * - If false, the event loop will not be started.
162+ *
163+ * @return void
164+ */
165+ private function startReact (bool $ start_loop = false ): void
166+ {
167+ $ this ->server ->listen ($ this ->socket );
168+ if ($ start_loop ) $ this ->loop ->run ();
169+ }
170+
171+ /**
172+ * Starts the resource handling loop for the server.
173+ *
174+ * This method continuously listens for incoming client connections
175+ * while the server is running. If the operating system is not Windows
176+ * and the `pcntl` extension is loaded, it dispatches pending signals
177+ * using `pcntl_signal_dispatch`. When a client connection is accepted,
178+ * it delegates the handling of the connection to the `handleResource` method.
179+ *
180+ * @return void
181+ */
182+ private function startResource (): void
183+ {
184+ while ($ this ->running ) {
185+ if (stripos (PHP_OS , 'WIN ' ) === false && extension_loaded ('pcntl ' )) {
186+ pcntl_signal_dispatch ();
155187 }
188+ ($ client = @stream_socket_accept ($ this ->server , 0 ))
189+ ? $ this ->handleResource ($ client )
190+ : $ this ->logError (new Exception ("Failed to accept client connection " ), true );
156191 }
157192 }
158193
@@ -214,6 +249,16 @@ public function getServer()
214249 return $ this ->server ?? null ;
215250 }
216251
252+ /**
253+ * Retrieves the socket instance.
254+ *
255+ * @return SocketServer|null Returns the socket instance if set, or null if not set.
256+ */
257+ public function getSocketServer (): SocketServer |null
258+ {
259+ return $ this ->socket ?? null ;
260+ }
261+
217262 /**
218263 * Retrieves the current state of the server.
219264 *
@@ -353,6 +398,27 @@ private function handleResource($client): null
353398 return null ;
354399 }
355400
401+ /**
402+ * Logs an error message with details about the exception.
403+ *
404+ * @param Exception $e The exception to log.
405+ * @param bool $fatal Optional. Indicates whether the error is fatal. Defaults to false.
406+ * If true, the server will stop after logging the error.
407+ *
408+ * @return string
409+ */
410+ public function logError (Exception $ e , bool $ fatal = false ): void
411+ {
412+ if ($ fatal ) $ this ->close ();
413+ if (isset ($ this ->logger )) $ this ->logger ->warning (sprintf (
414+ "Error: %s " . PHP_EOL . "Line %d in %s " . PHP_EOL . "%s " ,
415+ $ e ->getMessage (),
416+ $ e ->getLine (),
417+ $ e ->getFile (),
418+ $ e ->getTraceAsString ()
419+ ));
420+ }
421+
356422 /**
357423 * Destructor method that is automatically called when the object is destroyed.
358424 * It ensures that the server is properly stopped by calling the stop() method.
0 commit comments