@@ -71,6 +71,7 @@ class Process implements \IteratorAggregate
71
71
private $ incrementalErrorOutputOffset = 0 ;
72
72
private $ tty = false ;
73
73
private $ pty ;
74
+ private $ options = ['suppress_errors ' => true , 'bypass_shell ' => true ];
74
75
75
76
private $ useFileHandles = false ;
76
77
/** @var PipesInterface */
@@ -196,7 +197,11 @@ public static function fromShellCommandline(string $command, string $cwd = null,
196
197
197
198
public function __destruct ()
198
199
{
199
- $ this ->stop (0 );
200
+ if ($ this ->options ['create_new_console ' ] ?? false ) {
201
+ $ this ->processPipes ->close ();
202
+ } else {
203
+ $ this ->stop (0 );
204
+ }
200
205
}
201
206
202
207
public function __clone ()
@@ -303,10 +308,7 @@ public function start(callable $callback = null, array $env = [])
303
308
$ commandline = $ this ->replacePlaceholders ($ commandline , $ env );
304
309
}
305
310
306
- $ options = ['suppress_errors ' => true ];
307
-
308
311
if ('\\' === \DIRECTORY_SEPARATOR ) {
309
- $ options ['bypass_shell ' ] = true ;
310
312
$ commandline = $ this ->prepareWindowsCommandLine ($ commandline , $ env );
311
313
} elseif (!$ this ->useFileHandles && $ this ->isSigchildEnabled ()) {
312
314
// last exit code is output on the fourth pipe and caught to work around --enable-sigchild
@@ -332,7 +334,7 @@ public function start(callable $callback = null, array $env = [])
332
334
throw new RuntimeException (sprintf ('The provided cwd "%s" does not exist. ' , $ this ->cwd ));
333
335
}
334
336
335
- $ this ->process = @proc_open ($ commandline , $ descriptors , $ this ->processPipes ->pipes , $ this ->cwd , $ envPairs , $ options );
337
+ $ this ->process = @proc_open ($ commandline , $ descriptors , $ this ->processPipes ->pipes , $ this ->cwd , $ envPairs , $ this -> options );
336
338
337
339
if (!\is_resource ($ this ->process )) {
338
340
throw new RuntimeException ('Unable to launch a new process. ' );
@@ -1220,6 +1222,32 @@ public function getStartTime(): float
1220
1222
return $ this ->starttime ;
1221
1223
}
1222
1224
1225
+ /**
1226
+ * Defines options to pass to the underlying proc_open().
1227
+ *
1228
+ * @see https://php.net/proc_open for the options supported by PHP.
1229
+ *
1230
+ * Enabling the "create_new_console" option allows a subprocess to continue
1231
+ * to run after the main process exited, on both Windows and *nix
1232
+ */
1233
+ public function setOptions (array $ options )
1234
+ {
1235
+ if ($ this ->isRunning ()) {
1236
+ throw new RuntimeException ('Setting options while the process is running is not possible. ' );
1237
+ }
1238
+
1239
+ $ defaultOptions = $ this ->options ;
1240
+ $ existingOptions = ['blocking_pipes ' , 'create_process_group ' , 'create_new_console ' ];
1241
+
1242
+ foreach ($ options as $ key => $ value ) {
1243
+ if (!\in_array ($ key , $ existingOptions )) {
1244
+ $ this ->options = $ defaultOptions ;
1245
+ throw new LogicException (sprintf ('Invalid option "%s" passed to "%s()". Supported options are "%s". ' , $ key , __METHOD__ , implode ('", " ' , $ existingOptions )));
1246
+ }
1247
+ $ this ->options [$ key ] = $ value ;
1248
+ }
1249
+ }
1250
+
1223
1251
/**
1224
1252
* Returns whether TTY is supported on the current operating system.
1225
1253
*/
0 commit comments