99 */
1010namespace PHPUnit \Util \PHP ;
1111
12+ use function array_key_exists ;
13+ use function array_values ;
14+ use function function_exists ;
15+ use function hrtime ;
16+ use function ini_get ;
17+ use function is_array ;
18+ use function pack ;
19+ use function pcntl_fork ;
20+ use function serialize ;
21+ use function socket_close ;
22+ use function socket_create_pair ;
23+ use function socket_last_error ;
24+ use function socket_read ;
25+ use function socket_strerror ;
26+ use function socket_write ;
27+ use function str_contains ;
28+ use function strlen ;
29+ use function strtoupper ;
30+ use function substr ;
31+ use function unpack ;
32+ use function unserialize ;
33+ use Exception ;
1234use PHPUnit \Event \Facade ;
35+ use PHPUnit \Event \Telemetry \HRTime ;
1336use PHPUnit \Framework \TestCase ;
1437use PHPUnit \Runner \CodeCoverage ;
1538use PHPUnit \TestRunner \TestResult \PassedTests ;
39+ use RuntimeException ;
1640
17- final class PcntlFork {
41+ final class PcntlFork
42+ {
1843 // IPC inspired from https://github.com/barracudanetworks/forkdaemon-php
1944 private const SOCKET_HEADER_SIZE = 4 ;
2045
21- static public function isPcntlForkAvailable (): bool {
46+ public static function isPcntlForkAvailable (): bool
47+ {
2248 $ disabledFunctions = ini_get ('disable_functions ' );
2349
2450 return
25- function_exists ('pcntl_fork ' )
26- && !str_contains ($ disabledFunctions , 'pcntl ' )
27- && function_exists ('socket_create_pair ' )
28- && !str_contains ($ disabledFunctions , 'socket ' )
29- ;
51+ function_exists ('pcntl_fork ' ) &&
52+ !str_contains ($ disabledFunctions , 'pcntl ' ) &&
53+ function_exists ('socket_create_pair ' ) &&
54+ !str_contains ($ disabledFunctions , 'socket ' );
3055 }
3156
3257 public function runTest (TestCase $ test ): void
3358 {
34- list ( $ socket_child , $ socket_parent) = $ this ->ipcInit ();
59+ [ $ socket_child , $ socket_parent] = $ this ->ipcInit ();
3560
3661 $ pid = pcntl_fork ();
3762
38- if ($ pid === -1 ) {
39- throw new \Exception ('could not fork ' );
40- } else if ($ pid ) {
63+ if ($ pid === -1 ) {
64+ throw new Exception ('could not fork ' );
65+ }
66+
67+ if ($ pid ) {
4168 // we are the parent
4269
4370 socket_close ($ socket_parent );
@@ -47,6 +74,7 @@ public function runTest(TestCase $test): void
4774
4875 $ stderr = '' ;
4976 $ stdout = '' ;
77+
5078 if (is_array ($ result ) && array_key_exists ('error ' , $ result )) {
5179 $ stderr = $ result ['error ' ];
5280 } else {
@@ -61,19 +89,21 @@ public function runTest(TestCase $test): void
6189
6290 socket_close ($ socket_child );
6391
64- $ offset = hrtime ();
92+ $ offset = hrtime ();
6593 $ dispatcher = Facade::instance ()->initForIsolation (
66- \ PHPUnit \ Event \ Telemetry \ HRTime::fromSecondsAndNanoseconds (
94+ HRTime::fromSecondsAndNanoseconds (
6795 $ offset [0 ],
68- $ offset [1 ]
69- )
96+ $ offset [1 ],
97+ ),
7098 );
7199
72100 $ test ->setInIsolation (true );
101+
73102 try {
74103 $ test ->run ();
75104 } catch (Throwable $ e ) {
76105 $ this ->socketSend ($ socket_parent , ['error ' => $ e ->getMessage ()]);
106+
77107 exit ();
78108 }
79109
@@ -84,12 +114,13 @@ public function runTest(TestCase $test): void
84114 'numAssertions ' => $ test ->numberOfAssertionsPerformed (),
85115 'output ' => !$ test ->expectsOutput () ? $ test ->output () : '' ,
86116 'events ' => $ dispatcher ->flush (),
87- 'passedTests ' => PassedTests::instance ()
88- ]
117+ 'passedTests ' => PassedTests::instance (),
118+ ],
89119 );
90120
91121 // send result into parent
92122 $ this ->socketSend ($ socket_parent , $ result );
123+
93124 exit ();
94125 }
95126 }
@@ -100,10 +131,10 @@ private function ipcInit(): array
100131 $ domain = strtoupper (substr (PHP_OS , 0 , 3 )) == 'WIN ' ? AF_INET : AF_UNIX ;
101132
102133 // create a socket pair for IPC
103- $ sockets = array () ;
104- if ( socket_create_pair ( $ domain , SOCK_STREAM , 0 , $ sockets ) === false )
105- {
106- throw new \ RuntimeException ('socket_create_pair failed: ' . socket_strerror (socket_last_error ()));
134+ $ sockets = [] ;
135+
136+ if ( socket_create_pair ( $ domain , SOCK_STREAM , 0 , $ sockets ) === false ) {
137+ throw new RuntimeException ('socket_create_pair failed: ' . socket_strerror (socket_last_error ()));
107138 }
108139
109140 return $ sockets ;
@@ -116,32 +147,30 @@ private function socketReceive($socket): mixed
116147 {
117148 // initially read to the length of the header size, then
118149 // expand to read more
119- $ bytes_total = self ::SOCKET_HEADER_SIZE ;
120- $ bytes_read = 0 ;
121- $ have_header = false ;
150+ $ bytes_total = self ::SOCKET_HEADER_SIZE ;
151+ $ bytes_read = 0 ;
152+ $ have_header = false ;
122153 $ socket_message = '' ;
123- while ( $ bytes_read < $ bytes_total )
124- {
154+
155+ while ( $ bytes_read < $ bytes_total ) {
125156 $ read = @socket_read ($ socket , $ bytes_total - $ bytes_read );
126- if ( $ read === false )
127- {
128- throw new \ RuntimeException ('socket_receive error: ' . socket_strerror (socket_last_error ()));
157+
158+ if ( $ read === false ) {
159+ throw new RuntimeException ('socket_receive error: ' . socket_strerror (socket_last_error ()));
129160 }
130161
131162 // blank socket_read means done
132- if ($ read == '' )
133- {
163+ if ($ read == '' ) {
134164 break ;
135165 }
136166
137167 $ bytes_read += strlen ($ read );
138168 $ socket_message .= $ read ;
139169
140- if (!$ have_header && $ bytes_read >= self ::SOCKET_HEADER_SIZE )
141- {
142- $ have_header = true ;
143- list ($ bytes_total ) = array_values (unpack ('N ' , $ socket_message ));
144- $ bytes_read = 0 ;
170+ if (!$ have_header && $ bytes_read >= self ::SOCKET_HEADER_SIZE ) {
171+ $ have_header = true ;
172+ [$ bytes_total ] = array_values (unpack ('N ' , $ socket_message ));
173+ $ bytes_read = 0 ;
145174 $ socket_message = '' ;
146175 }
147176 }
@@ -151,25 +180,25 @@ private function socketReceive($socket): mixed
151180
152181 /**
153182 * @param resource $socket
154- * @param mixed $message
183+ * @param mixed $message
155184 */
156185 private function socketSend ($ socket , $ message ): void
157186 {
158187 $ serialized_message = @serialize ($ message );
159- if ( $ serialized_message == false )
160- {
161- throw new \ RuntimeException ('socket_send failed to serialize message ' );
188+
189+ if ( $ serialized_message == false ) {
190+ throw new RuntimeException ('socket_send failed to serialize message ' );
162191 }
163192
164- $ header = pack ('N ' , strlen ($ serialized_message ));
165- $ data = $ header . $ serialized_message ;
193+ $ header = pack ('N ' , strlen ($ serialized_message ));
194+ $ data = $ header . $ serialized_message ;
166195 $ bytes_left = strlen ($ data );
167- while ( $ bytes_left > 0 )
168- {
196+
197+ while ( $ bytes_left > 0 ) {
169198 $ bytes_sent = @socket_write ($ socket , $ data );
170- if ( $ bytes_sent === false )
171- {
172- throw new \ RuntimeException ('socket_send failed to write to socket ' );
199+
200+ if ( $ bytes_sent === false ) {
201+ throw new RuntimeException ('socket_send failed to write to socket ' );
173202 }
174203
175204 $ bytes_left -= $ bytes_sent ;
0 commit comments