1919use PHPStan \File \FileMonitorResult ;
2020use PHPStan \File \FileReader ;
2121use PHPStan \File \FileWriter ;
22+ use PHPStan \File \PathNotFoundException ;
2223use PHPStan \Internal \ComposerHelper ;
2324use PHPStan \Internal \DirectoryCreator ;
2425use PHPStan \Internal \DirectoryCreatorException ;
2526use PHPStan \Internal \HttpClientFactory ;
27+ use PHPStan \Parallel \ForkParallelChecker ;
2628use PHPStan \PhpDoc \StubFilesProvider ;
29+ use PHPStan \Process \ForkedProcessPromise ;
2730use PHPStan \Process \ProcessCanceledException ;
2831use PHPStan \Process \ProcessCrashedException ;
2932use PHPStan \Process \ProcessHelper ;
3033use PHPStan \Process \ProcessPromise ;
34+ use PHPStan \Process \SpawnedProcessPromise ;
3135use PHPStan \ShouldNotHappenException ;
3236use React \ChildProcess \Process ;
3337use React \EventLoop \LoopInterface ;
@@ -94,18 +98,22 @@ public function __construct(
9498 #[AutowiredParameter]
9599 private string $ usedLevel ,
96100 private HttpClientFactory $ httpClientFactory ,
101+ private ForkParallelChecker $ forkParallelChecker ,
102+ private FixerWorkerRunner $ fixerWorkerRunner ,
97103 )
98104 {
99105 }
100106
101107 public function run (
102- ? string $ projectConfigFile ,
108+ InceptionResult $ inceptionResult ,
103109 InputInterface $ input ,
104110 OutputInterface $ output ,
105111 int $ filesCount ,
106112 string $ mainScript ,
107113 ): int
108114 {
115+ $ projectConfigFile = $ inceptionResult ->getProjectConfigFile ();
116+
109117 $ loop = new StreamSelectLoop ();
110118 $ server = new TcpServer ('127.0.0.1:0 ' , $ loop );
111119 /** @var string $serverAddress */
@@ -114,7 +122,7 @@ public function run(
114122 /** @var int<0, 65535> $serverPort */
115123 $ serverPort = parse_url ($ serverAddress , PHP_URL_PORT );
116124
117- $ server ->on ('connection ' , function (ConnectionInterface $ connection ) use ($ loop , $ projectConfigFile , $ input , $ output , $ mainScript , $ filesCount ): void {
125+ $ server ->on ('connection ' , function (ConnectionInterface $ connection ) use ($ loop , $ inceptionResult , $ projectConfigFile , $ input , $ output , $ mainScript , $ filesCount ): void {
118126 // phpcs:disable SlevomatCodingStandard.Namespaces.ReferenceUsedNamesOnly
119127 $ jsonInvalidUtf8Ignore = defined ('JSON_INVALID_UTF8_IGNORE ' ) ? JSON_INVALID_UTF8_IGNORE : 0 ;
120128 // phpcs:enable
@@ -157,14 +165,15 @@ public function run(
157165
158166 $ this ->analyse (
159167 $ loop ,
168+ $ inceptionResult ,
160169 $ mainScript ,
161170 $ projectConfigFile ,
162171 $ input ,
163172 $ output ,
164173 $ encoder ,
165174 );
166175
167- $ this ->monitorFileChanges ($ loop , function (FileMonitorResult $ changes ) use ($ loop , $ mainScript , $ projectConfigFile , $ input , $ encoder , $ output ): void {
176+ $ this ->monitorFileChanges ($ loop , function (FileMonitorResult $ changes ) use ($ loop , $ inceptionResult , $ mainScript , $ projectConfigFile , $ input , $ encoder , $ output ): void {
168177 if ($ this ->processInProgress !== null ) {
169178 $ this ->processInProgress ->cancel ();
170179 $ this ->processInProgress = null ;
@@ -178,6 +187,7 @@ public function run(
178187
179188 $ this ->analyse (
180189 $ loop ,
190+ $ inceptionResult ,
181191 $ mainScript ,
182192 $ projectConfigFile ,
183193 $ input ,
@@ -417,6 +427,7 @@ private function monitorFileChanges(LoopInterface $loop, callable $hasChangesCal
417427
418428 private function analyse (
419429 LoopInterface $ loop ,
430+ InceptionResult $ inceptionResult ,
420431 string $ mainScript ,
421432 ?string $ projectConfigFile ,
422433 InputInterface $ input ,
@@ -446,16 +457,16 @@ private function analyse(
446457 });
447458 });
448459
449- $ process = new ProcessPromise ($ loop , ProcessHelper::getWorkerCommand (
460+ $ process = $ this ->createProcessPromise (
461+ $ this ->forkParallelChecker ->isSupported (),
462+ $ loop ,
463+ $ server ,
450464 $ mainScript ,
451- 'fixer:worker ' ,
452465 $ projectConfigFile ,
453- [
454- '--server-port ' ,
455- (string ) $ serverPort ,
456- ],
457466 $ input ,
458- ));
467+ $ serverPort ,
468+ $ inceptionResult ,
469+ );
459470 $ this ->processInProgress = $ process ->run ();
460471
461472 $ this ->processInProgress ->then (function () use ($ server ): void {
@@ -566,4 +577,51 @@ private function getStubFiles(): array
566577 return $ stubFiles ;
567578 }
568579
580+ /**
581+ * @param int<0, 65535> $serverPort
582+ */
583+ private function createProcessPromise (
584+ bool $ useFork ,
585+ LoopInterface $ loop ,
586+ TcpServer $ server ,
587+ string $ mainScript ,
588+ ?string $ projectConfigFile ,
589+ InputInterface $ input ,
590+ int $ serverPort ,
591+ InceptionResult $ inceptionResult ,
592+ ): ProcessPromise
593+ {
594+ if ($ useFork ) {
595+ try {
596+ [$ inceptionFiles , $ isOnlyFiles ] = $ inceptionResult ->getFiles ();
597+ } catch (PathNotFoundException | InceptionNotSuccessfulException ) {
598+ throw new ShouldNotHappenException ();
599+ }
600+
601+ return new ForkedProcessPromise (
602+ $ loop ,
603+ $ this ->fixerWorkerRunner ,
604+ $ server ,
605+ $ inceptionResult ->getErrorOutput (),
606+ $ inceptionFiles ,
607+ $ isOnlyFiles ,
608+ $ inceptionResult ->getProjectConfigArray (),
609+ $ projectConfigFile ,
610+ $ serverPort ,
611+ $ input ,
612+ );
613+ }
614+
615+ return new SpawnedProcessPromise ($ loop , ProcessHelper::getWorkerCommand (
616+ $ mainScript ,
617+ 'fixer:worker ' ,
618+ $ projectConfigFile ,
619+ [
620+ '--server-port ' ,
621+ (string ) $ serverPort ,
622+ ],
623+ $ input ,
624+ ));
625+ }
626+
569627}
0 commit comments