@@ -26,13 +26,16 @@ final class Process
2626
2727 private static \WeakMap $ procHolder ;
2828
29+ private static \WeakMap $ streamHolder ;
30+
2931 /**
3032 * Starts a new process.
3133 *
3234 * @param string|list<string> $command Command to run.
3335 * @param string|null $workingDirectory Working directory, or an empty string to use the working directory of the
3436 * parent.
35- * @param array<string, string> $environment Environment variables, or use an empty array to inherit from the parent.
37+ * @param array<string, string> $environment Environment variables, or use an empty array to inherit from the
38+ * parent.
3639 * @param array<string, bool> $options Options for {@see proc_open()}.
3740 *
3841 * @throws ProcessException If starting the process fails.
@@ -59,14 +62,6 @@ public static function start(
5962 ? \implode (" " , \array_map (escapeArgument (...), $ command ))
6063 : $ command ;
6164
62- $ driver = EventLoop::getDriver ();
63-
64- /** @psalm-suppress RedundantPropertyInitializationCheck */
65- self ::$ driverRunner ??= new \WeakMap ();
66- self ::$ driverRunner [$ driver ] ??= \PHP_OS_FAMILY === 'Windows '
67- ? new WindowsProcessRunner ()
68- : new PosixProcessRunner ();
69-
7065 if (!$ workingDirectory ) {
7166 $ cwd = \getcwd ();
7267 if ($ cwd === false ) {
@@ -76,7 +71,10 @@ public static function start(
7671 $ workingDirectory = $ cwd ;
7772 }
7873
79- $ runner = self ::$ driverRunner [$ driver ];
74+ $ driver = EventLoop::getDriver ();
75+
76+ $ runner = self ::$ driverRunner [$ driver ] ??= self ::initialize ();
77+
8078 $ context = $ runner ->start (
8179 $ command ,
8280 $ cancellation ?? new NullCancellation (),
@@ -90,13 +88,38 @@ public static function start(
9088
9189 $ procHolder = new ProcHolder ($ runner , $ handle );
9290
91+ self ::$ streamHolder [$ streams ->stdin ] = $ procHolder ;
92+ self ::$ streamHolder [$ streams ->stdout ] = $ procHolder ;
93+ self ::$ streamHolder [$ streams ->stderr ] = $ procHolder ;
94+
95+ self ::$ procHolder [$ procHolder ] = $ handle ->pid ;
96+
97+ return new self ($ runner , $ handle , $ streams , $ command , $ workingDirectory , $ envVars , $ options );
98+ }
99+
100+ private static function initialize (): ProcessRunner
101+ {
102+ /** @psalm-suppress RedundantPropertyInitializationCheck */
103+ self ::$ driverRunner ??= new \WeakMap ();
104+
93105 /** @psalm-suppress RedundantPropertyInitializationCheck */
94106 self ::$ procHolder ??= new \WeakMap ();
95- self ::$ procHolder [$ streams ->stdin ] = $ procHolder ;
96- self ::$ procHolder [$ streams ->stdout ] = $ procHolder ;
97- self ::$ procHolder [$ streams ->stderr ] = $ procHolder ;
98107
99- return new self ($ runner , $ handle , $ streams , $ command , $ workingDirectory , $ envVars , $ options );
108+ /** @psalm-suppress RedundantPropertyInitializationCheck */
109+ self ::$ streamHolder ??= new \WeakMap ();
110+
111+ $ runner = \PHP_OS_FAMILY === 'Windows '
112+ ? new WindowsProcessRunner ()
113+ : new PosixProcessRunner ();
114+
115+ \register_shutdown_function (static function (): void {
116+ /** @var ProcHolder $procHolder */
117+ foreach (self ::$ procHolder as $ procHolder => $ pid ) {
118+ $ procHolder ->handle ->wait ();
119+ }
120+ });
121+
122+ return $ runner ;
100123 }
101124
102125 /**
0 commit comments