Completed
Pull Request — develop (#1656)
by
unknown
17:57
created
vendor/symfony/process/ExecutableFinder.php 3 patches
Indentation   +59 added lines, -59 removed lines patch added patch discarded remove patch
@@ -19,68 +19,68 @@
 block discarded – undo
19 19
  */
20 20
 class ExecutableFinder
21 21
 {
22
-    private $suffixes = ['.exe', '.bat', '.cmd', '.com'];
22
+	private $suffixes = ['.exe', '.bat', '.cmd', '.com'];
23 23
 
24
-    /**
25
-     * Replaces default suffixes of executable.
26
-     */
27
-    public function setSuffixes(array $suffixes)
28
-    {
29
-        $this->suffixes = $suffixes;
30
-    }
24
+	/**
25
+	 * Replaces default suffixes of executable.
26
+	 */
27
+	public function setSuffixes(array $suffixes)
28
+	{
29
+		$this->suffixes = $suffixes;
30
+	}
31 31
 
32
-    /**
33
-     * Adds new possible suffix to check for executable.
34
-     */
35
-    public function addSuffix(string $suffix)
36
-    {
37
-        $this->suffixes[] = $suffix;
38
-    }
32
+	/**
33
+	 * Adds new possible suffix to check for executable.
34
+	 */
35
+	public function addSuffix(string $suffix)
36
+	{
37
+		$this->suffixes[] = $suffix;
38
+	}
39 39
 
40
-    /**
41
-     * Finds an executable by name.
42
-     *
43
-     * @param string      $name      The executable name (without the extension)
44
-     * @param string|null $default   The default to return if no executable is found
45
-     * @param array       $extraDirs Additional dirs to check into
46
-     *
47
-     * @return string|null The executable path or default value
48
-     */
49
-    public function find(string $name, string $default = null, array $extraDirs = [])
50
-    {
51
-        if (ini_get('open_basedir')) {
52
-            $searchPath = array_merge(explode(\PATH_SEPARATOR, ini_get('open_basedir')), $extraDirs);
53
-            $dirs = [];
54
-            foreach ($searchPath as $path) {
55
-                // Silencing against https://bugs.php.net/69240
56
-                if (@is_dir($path)) {
57
-                    $dirs[] = $path;
58
-                } else {
59
-                    if (basename($path) == $name && @is_executable($path)) {
60
-                        return $path;
61
-                    }
62
-                }
63
-            }
64
-        } else {
65
-            $dirs = array_merge(
66
-                explode(\PATH_SEPARATOR, getenv('PATH') ?: getenv('Path')),
67
-                $extraDirs
68
-            );
69
-        }
40
+	/**
41
+	 * Finds an executable by name.
42
+	 *
43
+	 * @param string      $name      The executable name (without the extension)
44
+	 * @param string|null $default   The default to return if no executable is found
45
+	 * @param array       $extraDirs Additional dirs to check into
46
+	 *
47
+	 * @return string|null The executable path or default value
48
+	 */
49
+	public function find(string $name, string $default = null, array $extraDirs = [])
50
+	{
51
+		if (ini_get('open_basedir')) {
52
+			$searchPath = array_merge(explode(\PATH_SEPARATOR, ini_get('open_basedir')), $extraDirs);
53
+			$dirs = [];
54
+			foreach ($searchPath as $path) {
55
+				// Silencing against https://bugs.php.net/69240
56
+				if (@is_dir($path)) {
57
+					$dirs[] = $path;
58
+				} else {
59
+					if (basename($path) == $name && @is_executable($path)) {
60
+						return $path;
61
+					}
62
+				}
63
+			}
64
+		} else {
65
+			$dirs = array_merge(
66
+				explode(\PATH_SEPARATOR, getenv('PATH') ?: getenv('Path')),
67
+				$extraDirs
68
+			);
69
+		}
70 70
 
71
-        $suffixes = [''];
72
-        if ('\\' === \DIRECTORY_SEPARATOR) {
73
-            $pathExt = getenv('PATHEXT');
74
-            $suffixes = array_merge($pathExt ? explode(\PATH_SEPARATOR, $pathExt) : $this->suffixes, $suffixes);
75
-        }
76
-        foreach ($suffixes as $suffix) {
77
-            foreach ($dirs as $dir) {
78
-                if (@is_file($file = $dir.\DIRECTORY_SEPARATOR.$name.$suffix) && ('\\' === \DIRECTORY_SEPARATOR || @is_executable($file))) {
79
-                    return $file;
80
-                }
81
-            }
82
-        }
71
+		$suffixes = [''];
72
+		if ('\\' === \DIRECTORY_SEPARATOR) {
73
+			$pathExt = getenv('PATHEXT');
74
+			$suffixes = array_merge($pathExt ? explode(\PATH_SEPARATOR, $pathExt) : $this->suffixes, $suffixes);
75
+		}
76
+		foreach ($suffixes as $suffix) {
77
+			foreach ($dirs as $dir) {
78
+				if (@is_file($file = $dir.\DIRECTORY_SEPARATOR.$name.$suffix) && ('\\' === \DIRECTORY_SEPARATOR || @is_executable($file))) {
79
+					return $file;
80
+				}
81
+			}
82
+		}
83 83
 
84
-        return $default;
85
-    }
84
+		return $default;
85
+	}
86 86
 }
Please login to merge, or discard this patch.
Spacing   +20 added lines, -20 removed lines patch added patch discarded remove patch
@@ -19,12 +19,12 @@  discard block
 block discarded – undo
19 19
  */
20 20
 class ExecutableFinder
21 21
 {
22
-    private $suffixes = ['.exe', '.bat', '.cmd', '.com'];
22
+    private $suffixes = [ '.exe', '.bat', '.cmd', '.com' ];
23 23
 
24 24
     /**
25 25
      * Replaces default suffixes of executable.
26 26
      */
27
-    public function setSuffixes(array $suffixes)
27
+    public function setSuffixes( array $suffixes )
28 28
     {
29 29
         $this->suffixes = $suffixes;
30 30
     }
@@ -32,9 +32,9 @@  discard block
 block discarded – undo
32 32
     /**
33 33
      * Adds new possible suffix to check for executable.
34 34
      */
35
-    public function addSuffix(string $suffix)
35
+    public function addSuffix( string $suffix )
36 36
     {
37
-        $this->suffixes[] = $suffix;
37
+        $this->suffixes[ ] = $suffix;
38 38
     }
39 39
 
40 40
     /**
@@ -46,36 +46,36 @@  discard block
 block discarded – undo
46 46
      *
47 47
      * @return string|null The executable path or default value
48 48
      */
49
-    public function find(string $name, string $default = null, array $extraDirs = [])
49
+    public function find( string $name, string $default = null, array $extraDirs = [ ] )
50 50
     {
51
-        if (ini_get('open_basedir')) {
52
-            $searchPath = array_merge(explode(\PATH_SEPARATOR, ini_get('open_basedir')), $extraDirs);
53
-            $dirs = [];
54
-            foreach ($searchPath as $path) {
51
+        if ( ini_get( 'open_basedir' ) ) {
52
+            $searchPath = array_merge( explode( \PATH_SEPARATOR, ini_get( 'open_basedir' ) ), $extraDirs );
53
+            $dirs = [ ];
54
+            foreach ( $searchPath as $path ) {
55 55
                 // Silencing against https://bugs.php.net/69240
56
-                if (@is_dir($path)) {
57
-                    $dirs[] = $path;
56
+                if ( @is_dir( $path ) ) {
57
+                    $dirs[ ] = $path;
58 58
                 } else {
59
-                    if (basename($path) == $name && @is_executable($path)) {
59
+                    if ( basename( $path ) == $name && @is_executable( $path ) ) {
60 60
                         return $path;
61 61
                     }
62 62
                 }
63 63
             }
64 64
         } else {
65 65
             $dirs = array_merge(
66
-                explode(\PATH_SEPARATOR, getenv('PATH') ?: getenv('Path')),
66
+                explode( \PATH_SEPARATOR, getenv( 'PATH' ) ?: getenv( 'Path' ) ),
67 67
                 $extraDirs
68 68
             );
69 69
         }
70 70
 
71
-        $suffixes = [''];
72
-        if ('\\' === \DIRECTORY_SEPARATOR) {
73
-            $pathExt = getenv('PATHEXT');
74
-            $suffixes = array_merge($pathExt ? explode(\PATH_SEPARATOR, $pathExt) : $this->suffixes, $suffixes);
71
+        $suffixes = [ '' ];
72
+        if ( '\\' === \DIRECTORY_SEPARATOR ) {
73
+            $pathExt = getenv( 'PATHEXT' );
74
+            $suffixes = array_merge( $pathExt ? explode( \PATH_SEPARATOR, $pathExt ) : $this->suffixes, $suffixes );
75 75
         }
76
-        foreach ($suffixes as $suffix) {
77
-            foreach ($dirs as $dir) {
78
-                if (@is_file($file = $dir.\DIRECTORY_SEPARATOR.$name.$suffix) && ('\\' === \DIRECTORY_SEPARATOR || @is_executable($file))) {
76
+        foreach ( $suffixes as $suffix ) {
77
+            foreach ( $dirs as $dir ) {
78
+                if ( @is_file( $file = $dir . \DIRECTORY_SEPARATOR . $name . $suffix ) && ( '\\' === \DIRECTORY_SEPARATOR || @is_executable( $file ) ) ) {
79 79
                     return $file;
80 80
                 }
81 81
             }
Please login to merge, or discard this patch.
Braces   +4 added lines, -8 removed lines patch added patch discarded remove patch
@@ -17,23 +17,20 @@  discard block
 block discarded – undo
17 17
  * @author Fabien Potencier <[email protected]>
18 18
  * @author Johannes M. Schmitt <[email protected]>
19 19
  */
20
-class ExecutableFinder
21
-{
20
+class ExecutableFinder {
22 21
     private $suffixes = ['.exe', '.bat', '.cmd', '.com'];
23 22
 
24 23
     /**
25 24
      * Replaces default suffixes of executable.
26 25
      */
27
-    public function setSuffixes(array $suffixes)
28
-    {
26
+    public function setSuffixes(array $suffixes) {
29 27
         $this->suffixes = $suffixes;
30 28
     }
31 29
 
32 30
     /**
33 31
      * Adds new possible suffix to check for executable.
34 32
      */
35
-    public function addSuffix(string $suffix)
36
-    {
33
+    public function addSuffix(string $suffix) {
37 34
         $this->suffixes[] = $suffix;
38 35
     }
39 36
 
@@ -46,8 +43,7 @@  discard block
 block discarded – undo
46 43
      *
47 44
      * @return string|null The executable path or default value
48 45
      */
49
-    public function find(string $name, string $default = null, array $extraDirs = [])
50
-    {
46
+    public function find(string $name, string $default = null, array $extraDirs = []) {
51 47
         if (ini_get('open_basedir')) {
52 48
             $searchPath = array_merge(explode(\PATH_SEPARATOR, ini_get('open_basedir')), $extraDirs);
53 49
             $dirs = [];
Please login to merge, or discard this patch.
vendor/symfony/process/Process.php 3 patches
Indentation   +1639 added lines, -1639 removed lines patch added patch discarded remove patch
@@ -30,1649 +30,1649 @@
 block discarded – undo
30 30
  */
31 31
 class Process implements \IteratorAggregate
32 32
 {
33
-    public const ERR = 'err';
34
-    public const OUT = 'out';
35
-
36
-    public const STATUS_READY = 'ready';
37
-    public const STATUS_STARTED = 'started';
38
-    public const STATUS_TERMINATED = 'terminated';
39
-
40
-    public const STDIN = 0;
41
-    public const STDOUT = 1;
42
-    public const STDERR = 2;
43
-
44
-    // Timeout Precision in seconds.
45
-    public const TIMEOUT_PRECISION = 0.2;
46
-
47
-    public const ITER_NON_BLOCKING = 1; // By default, iterating over outputs is a blocking call, use this flag to make it non-blocking
48
-    public const ITER_KEEP_OUTPUT = 2;  // By default, outputs are cleared while iterating, use this flag to keep them in memory
49
-    public const ITER_SKIP_OUT = 4;     // Use this flag to skip STDOUT while iterating
50
-    public const ITER_SKIP_ERR = 8;     // Use this flag to skip STDERR while iterating
51
-
52
-    private $callback;
53
-    private $hasCallback = false;
54
-    private $commandline;
55
-    private $cwd;
56
-    private $env;
57
-    private $input;
58
-    private $starttime;
59
-    private $lastOutputTime;
60
-    private $timeout;
61
-    private $idleTimeout;
62
-    private $exitcode;
63
-    private $fallbackStatus = [];
64
-    private $processInformation;
65
-    private $outputDisabled = false;
66
-    private $stdout;
67
-    private $stderr;
68
-    private $process;
69
-    private $status = self::STATUS_READY;
70
-    private $incrementalOutputOffset = 0;
71
-    private $incrementalErrorOutputOffset = 0;
72
-    private $tty = false;
73
-    private $pty;
74
-    private $options = ['suppress_errors' => true, 'bypass_shell' => true];
75
-
76
-    private $useFileHandles = false;
77
-    /** @var PipesInterface */
78
-    private $processPipes;
79
-
80
-    private $latestSignal;
81
-
82
-    private static $sigchild;
83
-
84
-    /**
85
-     * Exit codes translation table.
86
-     *
87
-     * User-defined errors must use exit codes in the 64-113 range.
88
-     */
89
-    public static $exitCodes = [
90
-        0 => 'OK',
91
-        1 => 'General error',
92
-        2 => 'Misuse of shell builtins',
93
-
94
-        126 => 'Invoked command cannot execute',
95
-        127 => 'Command not found',
96
-        128 => 'Invalid exit argument',
97
-
98
-        // signals
99
-        129 => 'Hangup',
100
-        130 => 'Interrupt',
101
-        131 => 'Quit and dump core',
102
-        132 => 'Illegal instruction',
103
-        133 => 'Trace/breakpoint trap',
104
-        134 => 'Process aborted',
105
-        135 => 'Bus error: "access to undefined portion of memory object"',
106
-        136 => 'Floating point exception: "erroneous arithmetic operation"',
107
-        137 => 'Kill (terminate immediately)',
108
-        138 => 'User-defined 1',
109
-        139 => 'Segmentation violation',
110
-        140 => 'User-defined 2',
111
-        141 => 'Write to pipe with no one reading',
112
-        142 => 'Signal raised by alarm',
113
-        143 => 'Termination (request to terminate)',
114
-        // 144 - not defined
115
-        145 => 'Child process terminated, stopped (or continued*)',
116
-        146 => 'Continue if stopped',
117
-        147 => 'Stop executing temporarily',
118
-        148 => 'Terminal stop signal',
119
-        149 => 'Background process attempting to read from tty ("in")',
120
-        150 => 'Background process attempting to write to tty ("out")',
121
-        151 => 'Urgent data available on socket',
122
-        152 => 'CPU time limit exceeded',
123
-        153 => 'File size limit exceeded',
124
-        154 => 'Signal raised by timer counting virtual time: "virtual timer expired"',
125
-        155 => 'Profiling timer expired',
126
-        // 156 - not defined
127
-        157 => 'Pollable event',
128
-        // 158 - not defined
129
-        159 => 'Bad syscall',
130
-    ];
131
-
132
-    /**
133
-     * @param array          $command The command to run and its arguments listed as separate entries
134
-     * @param string|null    $cwd     The working directory or null to use the working dir of the current PHP process
135
-     * @param array|null     $env     The environment variables or null to use the same environment as the current PHP process
136
-     * @param mixed          $input   The input as stream resource, scalar or \Traversable, or null for no input
137
-     * @param int|float|null $timeout The timeout in seconds or null to disable
138
-     *
139
-     * @throws LogicException When proc_open is not installed
140
-     */
141
-    public function __construct(array $command, string $cwd = null, array $env = null, $input = null, ?float $timeout = 60)
142
-    {
143
-        if (!\function_exists('proc_open')) {
144
-            throw new LogicException('The Process class relies on proc_open, which is not available on your PHP installation.');
145
-        }
146
-
147
-        $this->commandline = $command;
148
-        $this->cwd = $cwd;
149
-
150
-        // on Windows, if the cwd changed via chdir(), proc_open defaults to the dir where PHP was started
151
-        // on Gnu/Linux, PHP builds with --enable-maintainer-zts are also affected
152
-        // @see : https://bugs.php.net/51800
153
-        // @see : https://bugs.php.net/50524
154
-        if (null === $this->cwd && (\defined('ZEND_THREAD_SAFE') || '\\' === \DIRECTORY_SEPARATOR)) {
155
-            $this->cwd = getcwd();
156
-        }
157
-        if (null !== $env) {
158
-            $this->setEnv($env);
159
-        }
160
-
161
-        $this->setInput($input);
162
-        $this->setTimeout($timeout);
163
-        $this->useFileHandles = '\\' === \DIRECTORY_SEPARATOR;
164
-        $this->pty = false;
165
-    }
166
-
167
-    /**
168
-     * Creates a Process instance as a command-line to be run in a shell wrapper.
169
-     *
170
-     * Command-lines are parsed by the shell of your OS (/bin/sh on Unix-like, cmd.exe on Windows.)
171
-     * This allows using e.g. pipes or conditional execution. In this mode, signals are sent to the
172
-     * shell wrapper and not to your commands.
173
-     *
174
-     * In order to inject dynamic values into command-lines, we strongly recommend using placeholders.
175
-     * This will save escaping values, which is not portable nor secure anyway:
176
-     *
177
-     *   $process = Process::fromShellCommandline('my_command "$MY_VAR"');
178
-     *   $process->run(null, ['MY_VAR' => $theValue]);
179
-     *
180
-     * @param string         $command The command line to pass to the shell of the OS
181
-     * @param string|null    $cwd     The working directory or null to use the working dir of the current PHP process
182
-     * @param array|null     $env     The environment variables or null to use the same environment as the current PHP process
183
-     * @param mixed          $input   The input as stream resource, scalar or \Traversable, or null for no input
184
-     * @param int|float|null $timeout The timeout in seconds or null to disable
185
-     *
186
-     * @return static
187
-     *
188
-     * @throws LogicException When proc_open is not installed
189
-     */
190
-    public static function fromShellCommandline(string $command, string $cwd = null, array $env = null, $input = null, ?float $timeout = 60)
191
-    {
192
-        $process = new static([], $cwd, $env, $input, $timeout);
193
-        $process->commandline = $command;
194
-
195
-        return $process;
196
-    }
197
-
198
-    /**
199
-     * @return array
200
-     */
201
-    public function __sleep()
202
-    {
203
-        throw new \BadMethodCallException('Cannot serialize '.__CLASS__);
204
-    }
205
-
206
-    public function __wakeup()
207
-    {
208
-        throw new \BadMethodCallException('Cannot unserialize '.__CLASS__);
209
-    }
210
-
211
-    public function __destruct()
212
-    {
213
-        if ($this->options['create_new_console'] ?? false) {
214
-            $this->processPipes->close();
215
-        } else {
216
-            $this->stop(0);
217
-        }
218
-    }
219
-
220
-    public function __clone()
221
-    {
222
-        $this->resetProcessData();
223
-    }
224
-
225
-    /**
226
-     * Runs the process.
227
-     *
228
-     * The callback receives the type of output (out or err) and
229
-     * some bytes from the output in real-time. It allows to have feedback
230
-     * from the independent process during execution.
231
-     *
232
-     * The STDOUT and STDERR are also available after the process is finished
233
-     * via the getOutput() and getErrorOutput() methods.
234
-     *
235
-     * @param callable|null $callback A PHP callback to run whenever there is some
236
-     *                                output available on STDOUT or STDERR
237
-     *
238
-     * @return int The exit status code
239
-     *
240
-     * @throws RuntimeException         When process can't be launched
241
-     * @throws RuntimeException         When process is already running
242
-     * @throws ProcessTimedOutException When process timed out
243
-     * @throws ProcessSignaledException When process stopped after receiving signal
244
-     * @throws LogicException           In case a callback is provided and output has been disabled
245
-     *
246
-     * @final
247
-     */
248
-    public function run(callable $callback = null, array $env = []): int
249
-    {
250
-        $this->start($callback, $env);
251
-
252
-        return $this->wait();
253
-    }
254
-
255
-    /**
256
-     * Runs the process.
257
-     *
258
-     * This is identical to run() except that an exception is thrown if the process
259
-     * exits with a non-zero exit code.
260
-     *
261
-     * @return $this
262
-     *
263
-     * @throws ProcessFailedException if the process didn't terminate successfully
264
-     *
265
-     * @final
266
-     */
267
-    public function mustRun(callable $callback = null, array $env = []): self
268
-    {
269
-        if (0 !== $this->run($callback, $env)) {
270
-            throw new ProcessFailedException($this);
271
-        }
272
-
273
-        return $this;
274
-    }
275
-
276
-    /**
277
-     * Starts the process and returns after writing the input to STDIN.
278
-     *
279
-     * This method blocks until all STDIN data is sent to the process then it
280
-     * returns while the process runs in the background.
281
-     *
282
-     * The termination of the process can be awaited with wait().
283
-     *
284
-     * The callback receives the type of output (out or err) and some bytes from
285
-     * the output in real-time while writing the standard input to the process.
286
-     * It allows to have feedback from the independent process during execution.
287
-     *
288
-     * @param callable|null $callback A PHP callback to run whenever there is some
289
-     *                                output available on STDOUT or STDERR
290
-     *
291
-     * @throws RuntimeException When process can't be launched
292
-     * @throws RuntimeException When process is already running
293
-     * @throws LogicException   In case a callback is provided and output has been disabled
294
-     */
295
-    public function start(callable $callback = null, array $env = [])
296
-    {
297
-        if ($this->isRunning()) {
298
-            throw new RuntimeException('Process is already running.');
299
-        }
300
-
301
-        $this->resetProcessData();
302
-        $this->starttime = $this->lastOutputTime = microtime(true);
303
-        $this->callback = $this->buildCallback($callback);
304
-        $this->hasCallback = null !== $callback;
305
-        $descriptors = $this->getDescriptors();
306
-
307
-        if ($this->env) {
308
-            $env += $this->env;
309
-        }
310
-
311
-        $env += $this->getDefaultEnv();
312
-
313
-        if (\is_array($commandline = $this->commandline)) {
314
-            $commandline = implode(' ', array_map([$this, 'escapeArgument'], $commandline));
315
-
316
-            if ('\\' !== \DIRECTORY_SEPARATOR) {
317
-                // exec is mandatory to deal with sending a signal to the process
318
-                $commandline = 'exec '.$commandline;
319
-            }
320
-        } else {
321
-            $commandline = $this->replacePlaceholders($commandline, $env);
322
-        }
323
-
324
-        if ('\\' === \DIRECTORY_SEPARATOR) {
325
-            $commandline = $this->prepareWindowsCommandLine($commandline, $env);
326
-        } elseif (!$this->useFileHandles && $this->isSigchildEnabled()) {
327
-            // last exit code is output on the fourth pipe and caught to work around --enable-sigchild
328
-            $descriptors[3] = ['pipe', 'w'];
329
-
330
-            // See https://unix.stackexchange.com/questions/71205/background-process-pipe-input
331
-            $commandline = '{ ('.$commandline.') <&3 3<&- 3>/dev/null & } 3<&0;';
332
-            $commandline .= 'pid=$!; echo $pid >&3; wait $pid; code=$?; echo $code >&3; exit $code';
333
-
334
-            // Workaround for the bug, when PTS functionality is enabled.
335
-            // @see : https://bugs.php.net/69442
336
-            $ptsWorkaround = fopen(__FILE__, 'r');
337
-        }
338
-
339
-        $envPairs = [];
340
-        foreach ($env as $k => $v) {
341
-            if (false !== $v) {
342
-                $envPairs[] = $k.'='.$v;
343
-            }
344
-        }
345
-
346
-        if (!is_dir($this->cwd)) {
347
-            throw new RuntimeException(sprintf('The provided cwd "%s" does not exist.', $this->cwd));
348
-        }
349
-
350
-        $this->process = @proc_open($commandline, $descriptors, $this->processPipes->pipes, $this->cwd, $envPairs, $this->options);
351
-
352
-        if (!\is_resource($this->process)) {
353
-            throw new RuntimeException('Unable to launch a new process.');
354
-        }
355
-        $this->status = self::STATUS_STARTED;
356
-
357
-        if (isset($descriptors[3])) {
358
-            $this->fallbackStatus['pid'] = (int) fgets($this->processPipes->pipes[3]);
359
-        }
360
-
361
-        if ($this->tty) {
362
-            return;
363
-        }
364
-
365
-        $this->updateStatus(false);
366
-        $this->checkTimeout();
367
-    }
368
-
369
-    /**
370
-     * Restarts the process.
371
-     *
372
-     * Be warned that the process is cloned before being started.
373
-     *
374
-     * @param callable|null $callback A PHP callback to run whenever there is some
375
-     *                                output available on STDOUT or STDERR
376
-     *
377
-     * @return static
378
-     *
379
-     * @throws RuntimeException When process can't be launched
380
-     * @throws RuntimeException When process is already running
381
-     *
382
-     * @see start()
383
-     *
384
-     * @final
385
-     */
386
-    public function restart(callable $callback = null, array $env = []): self
387
-    {
388
-        if ($this->isRunning()) {
389
-            throw new RuntimeException('Process is already running.');
390
-        }
391
-
392
-        $process = clone $this;
393
-        $process->start($callback, $env);
394
-
395
-        return $process;
396
-    }
397
-
398
-    /**
399
-     * Waits for the process to terminate.
400
-     *
401
-     * The callback receives the type of output (out or err) and some bytes
402
-     * from the output in real-time while writing the standard input to the process.
403
-     * It allows to have feedback from the independent process during execution.
404
-     *
405
-     * @param callable|null $callback A valid PHP callback
406
-     *
407
-     * @return int The exitcode of the process
408
-     *
409
-     * @throws ProcessTimedOutException When process timed out
410
-     * @throws ProcessSignaledException When process stopped after receiving signal
411
-     * @throws LogicException           When process is not yet started
412
-     */
413
-    public function wait(callable $callback = null)
414
-    {
415
-        $this->requireProcessIsStarted(__FUNCTION__);
416
-
417
-        $this->updateStatus(false);
418
-
419
-        if (null !== $callback) {
420
-            if (!$this->processPipes->haveReadSupport()) {
421
-                $this->stop(0);
422
-                throw new LogicException('Pass the callback to the "Process::start" method or call enableOutput to use a callback with "Process::wait".');
423
-            }
424
-            $this->callback = $this->buildCallback($callback);
425
-        }
426
-
427
-        do {
428
-            $this->checkTimeout();
429
-            $running = '\\' === \DIRECTORY_SEPARATOR ? $this->isRunning() : $this->processPipes->areOpen();
430
-            $this->readPipes($running, '\\' !== \DIRECTORY_SEPARATOR || !$running);
431
-        } while ($running);
432
-
433
-        while ($this->isRunning()) {
434
-            $this->checkTimeout();
435
-            usleep(1000);
436
-        }
437
-
438
-        if ($this->processInformation['signaled'] && $this->processInformation['termsig'] !== $this->latestSignal) {
439
-            throw new ProcessSignaledException($this);
440
-        }
441
-
442
-        return $this->exitcode;
443
-    }
444
-
445
-    /**
446
-     * Waits until the callback returns true.
447
-     *
448
-     * The callback receives the type of output (out or err) and some bytes
449
-     * from the output in real-time while writing the standard input to the process.
450
-     * It allows to have feedback from the independent process during execution.
451
-     *
452
-     * @throws RuntimeException         When process timed out
453
-     * @throws LogicException           When process is not yet started
454
-     * @throws ProcessTimedOutException In case the timeout was reached
455
-     */
456
-    public function waitUntil(callable $callback): bool
457
-    {
458
-        $this->requireProcessIsStarted(__FUNCTION__);
459
-        $this->updateStatus(false);
460
-
461
-        if (!$this->processPipes->haveReadSupport()) {
462
-            $this->stop(0);
463
-            throw new LogicException('Pass the callback to the "Process::start" method or call enableOutput to use a callback with "Process::waitUntil".');
464
-        }
465
-        $callback = $this->buildCallback($callback);
466
-
467
-        $ready = false;
468
-        while (true) {
469
-            $this->checkTimeout();
470
-            $running = '\\' === \DIRECTORY_SEPARATOR ? $this->isRunning() : $this->processPipes->areOpen();
471
-            $output = $this->processPipes->readAndWrite($running, '\\' !== \DIRECTORY_SEPARATOR || !$running);
472
-
473
-            foreach ($output as $type => $data) {
474
-                if (3 !== $type) {
475
-                    $ready = $callback(self::STDOUT === $type ? self::OUT : self::ERR, $data) || $ready;
476
-                } elseif (!isset($this->fallbackStatus['signaled'])) {
477
-                    $this->fallbackStatus['exitcode'] = (int) $data;
478
-                }
479
-            }
480
-            if ($ready) {
481
-                return true;
482
-            }
483
-            if (!$running) {
484
-                return false;
485
-            }
486
-
487
-            usleep(1000);
488
-        }
489
-    }
490
-
491
-    /**
492
-     * Returns the Pid (process identifier), if applicable.
493
-     *
494
-     * @return int|null The process id if running, null otherwise
495
-     */
496
-    public function getPid()
497
-    {
498
-        return $this->isRunning() ? $this->processInformation['pid'] : null;
499
-    }
500
-
501
-    /**
502
-     * Sends a POSIX signal to the process.
503
-     *
504
-     * @param int $signal A valid POSIX signal (see https://php.net/pcntl.constants)
505
-     *
506
-     * @return $this
507
-     *
508
-     * @throws LogicException   In case the process is not running
509
-     * @throws RuntimeException In case --enable-sigchild is activated and the process can't be killed
510
-     * @throws RuntimeException In case of failure
511
-     */
512
-    public function signal(int $signal)
513
-    {
514
-        $this->doSignal($signal, true);
515
-
516
-        return $this;
517
-    }
518
-
519
-    /**
520
-     * Disables fetching output and error output from the underlying process.
521
-     *
522
-     * @return $this
523
-     *
524
-     * @throws RuntimeException In case the process is already running
525
-     * @throws LogicException   if an idle timeout is set
526
-     */
527
-    public function disableOutput()
528
-    {
529
-        if ($this->isRunning()) {
530
-            throw new RuntimeException('Disabling output while the process is running is not possible.');
531
-        }
532
-        if (null !== $this->idleTimeout) {
533
-            throw new LogicException('Output can not be disabled while an idle timeout is set.');
534
-        }
535
-
536
-        $this->outputDisabled = true;
537
-
538
-        return $this;
539
-    }
540
-
541
-    /**
542
-     * Enables fetching output and error output from the underlying process.
543
-     *
544
-     * @return $this
545
-     *
546
-     * @throws RuntimeException In case the process is already running
547
-     */
548
-    public function enableOutput()
549
-    {
550
-        if ($this->isRunning()) {
551
-            throw new RuntimeException('Enabling output while the process is running is not possible.');
552
-        }
553
-
554
-        $this->outputDisabled = false;
555
-
556
-        return $this;
557
-    }
558
-
559
-    /**
560
-     * Returns true in case the output is disabled, false otherwise.
561
-     *
562
-     * @return bool
563
-     */
564
-    public function isOutputDisabled()
565
-    {
566
-        return $this->outputDisabled;
567
-    }
568
-
569
-    /**
570
-     * Returns the current output of the process (STDOUT).
571
-     *
572
-     * @return string The process output
573
-     *
574
-     * @throws LogicException in case the output has been disabled
575
-     * @throws LogicException In case the process is not started
576
-     */
577
-    public function getOutput()
578
-    {
579
-        $this->readPipesForOutput(__FUNCTION__);
580
-
581
-        if (false === $ret = stream_get_contents($this->stdout, -1, 0)) {
582
-            return '';
583
-        }
584
-
585
-        return $ret;
586
-    }
587
-
588
-    /**
589
-     * Returns the output incrementally.
590
-     *
591
-     * In comparison with the getOutput method which always return the whole
592
-     * output, this one returns the new output since the last call.
593
-     *
594
-     * @return string The process output since the last call
595
-     *
596
-     * @throws LogicException in case the output has been disabled
597
-     * @throws LogicException In case the process is not started
598
-     */
599
-    public function getIncrementalOutput()
600
-    {
601
-        $this->readPipesForOutput(__FUNCTION__);
602
-
603
-        $latest = stream_get_contents($this->stdout, -1, $this->incrementalOutputOffset);
604
-        $this->incrementalOutputOffset = ftell($this->stdout);
605
-
606
-        if (false === $latest) {
607
-            return '';
608
-        }
609
-
610
-        return $latest;
611
-    }
612
-
613
-    /**
614
-     * Returns an iterator to the output of the process, with the output type as keys (Process::OUT/ERR).
615
-     *
616
-     * @param int $flags A bit field of Process::ITER_* flags
617
-     *
618
-     * @throws LogicException in case the output has been disabled
619
-     * @throws LogicException In case the process is not started
620
-     *
621
-     * @return \Generator
622
-     */
623
-    #[\ReturnTypeWillChange]
624
-    public function getIterator(int $flags = 0)
625
-    {
626
-        $this->readPipesForOutput(__FUNCTION__, false);
627
-
628
-        $clearOutput = !(self::ITER_KEEP_OUTPUT & $flags);
629
-        $blocking = !(self::ITER_NON_BLOCKING & $flags);
630
-        $yieldOut = !(self::ITER_SKIP_OUT & $flags);
631
-        $yieldErr = !(self::ITER_SKIP_ERR & $flags);
632
-
633
-        while (null !== $this->callback || ($yieldOut && !feof($this->stdout)) || ($yieldErr && !feof($this->stderr))) {
634
-            if ($yieldOut) {
635
-                $out = stream_get_contents($this->stdout, -1, $this->incrementalOutputOffset);
636
-
637
-                if (isset($out[0])) {
638
-                    if ($clearOutput) {
639
-                        $this->clearOutput();
640
-                    } else {
641
-                        $this->incrementalOutputOffset = ftell($this->stdout);
642
-                    }
643
-
644
-                    yield self::OUT => $out;
645
-                }
646
-            }
647
-
648
-            if ($yieldErr) {
649
-                $err = stream_get_contents($this->stderr, -1, $this->incrementalErrorOutputOffset);
650
-
651
-                if (isset($err[0])) {
652
-                    if ($clearOutput) {
653
-                        $this->clearErrorOutput();
654
-                    } else {
655
-                        $this->incrementalErrorOutputOffset = ftell($this->stderr);
656
-                    }
657
-
658
-                    yield self::ERR => $err;
659
-                }
660
-            }
661
-
662
-            if (!$blocking && !isset($out[0]) && !isset($err[0])) {
663
-                yield self::OUT => '';
664
-            }
665
-
666
-            $this->checkTimeout();
667
-            $this->readPipesForOutput(__FUNCTION__, $blocking);
668
-        }
669
-    }
670
-
671
-    /**
672
-     * Clears the process output.
673
-     *
674
-     * @return $this
675
-     */
676
-    public function clearOutput()
677
-    {
678
-        ftruncate($this->stdout, 0);
679
-        fseek($this->stdout, 0);
680
-        $this->incrementalOutputOffset = 0;
681
-
682
-        return $this;
683
-    }
684
-
685
-    /**
686
-     * Returns the current error output of the process (STDERR).
687
-     *
688
-     * @return string The process error output
689
-     *
690
-     * @throws LogicException in case the output has been disabled
691
-     * @throws LogicException In case the process is not started
692
-     */
693
-    public function getErrorOutput()
694
-    {
695
-        $this->readPipesForOutput(__FUNCTION__);
696
-
697
-        if (false === $ret = stream_get_contents($this->stderr, -1, 0)) {
698
-            return '';
699
-        }
700
-
701
-        return $ret;
702
-    }
703
-
704
-    /**
705
-     * Returns the errorOutput incrementally.
706
-     *
707
-     * In comparison with the getErrorOutput method which always return the
708
-     * whole error output, this one returns the new error output since the last
709
-     * call.
710
-     *
711
-     * @return string The process error output since the last call
712
-     *
713
-     * @throws LogicException in case the output has been disabled
714
-     * @throws LogicException In case the process is not started
715
-     */
716
-    public function getIncrementalErrorOutput()
717
-    {
718
-        $this->readPipesForOutput(__FUNCTION__);
719
-
720
-        $latest = stream_get_contents($this->stderr, -1, $this->incrementalErrorOutputOffset);
721
-        $this->incrementalErrorOutputOffset = ftell($this->stderr);
722
-
723
-        if (false === $latest) {
724
-            return '';
725
-        }
726
-
727
-        return $latest;
728
-    }
729
-
730
-    /**
731
-     * Clears the process output.
732
-     *
733
-     * @return $this
734
-     */
735
-    public function clearErrorOutput()
736
-    {
737
-        ftruncate($this->stderr, 0);
738
-        fseek($this->stderr, 0);
739
-        $this->incrementalErrorOutputOffset = 0;
740
-
741
-        return $this;
742
-    }
743
-
744
-    /**
745
-     * Returns the exit code returned by the process.
746
-     *
747
-     * @return int|null The exit status code, null if the Process is not terminated
748
-     */
749
-    public function getExitCode()
750
-    {
751
-        $this->updateStatus(false);
752
-
753
-        return $this->exitcode;
754
-    }
755
-
756
-    /**
757
-     * Returns a string representation for the exit code returned by the process.
758
-     *
759
-     * This method relies on the Unix exit code status standardization
760
-     * and might not be relevant for other operating systems.
761
-     *
762
-     * @return string|null A string representation for the exit status code, null if the Process is not terminated
763
-     *
764
-     * @see http://tldp.org/LDP/abs/html/exitcodes.html
765
-     * @see http://en.wikipedia.org/wiki/Unix_signal
766
-     */
767
-    public function getExitCodeText()
768
-    {
769
-        if (null === $exitcode = $this->getExitCode()) {
770
-            return null;
771
-        }
772
-
773
-        return self::$exitCodes[$exitcode] ?? 'Unknown error';
774
-    }
775
-
776
-    /**
777
-     * Checks if the process ended successfully.
778
-     *
779
-     * @return bool true if the process ended successfully, false otherwise
780
-     */
781
-    public function isSuccessful()
782
-    {
783
-        return 0 === $this->getExitCode();
784
-    }
785
-
786
-    /**
787
-     * Returns true if the child process has been terminated by an uncaught signal.
788
-     *
789
-     * It always returns false on Windows.
790
-     *
791
-     * @return bool
792
-     *
793
-     * @throws LogicException In case the process is not terminated
794
-     */
795
-    public function hasBeenSignaled()
796
-    {
797
-        $this->requireProcessIsTerminated(__FUNCTION__);
798
-
799
-        return $this->processInformation['signaled'];
800
-    }
801
-
802
-    /**
803
-     * Returns the number of the signal that caused the child process to terminate its execution.
804
-     *
805
-     * It is only meaningful if hasBeenSignaled() returns true.
806
-     *
807
-     * @return int
808
-     *
809
-     * @throws RuntimeException In case --enable-sigchild is activated
810
-     * @throws LogicException   In case the process is not terminated
811
-     */
812
-    public function getTermSignal()
813
-    {
814
-        $this->requireProcessIsTerminated(__FUNCTION__);
815
-
816
-        if ($this->isSigchildEnabled() && -1 === $this->processInformation['termsig']) {
817
-            throw new RuntimeException('This PHP has been compiled with --enable-sigchild. Term signal can not be retrieved.');
818
-        }
819
-
820
-        return $this->processInformation['termsig'];
821
-    }
822
-
823
-    /**
824
-     * Returns true if the child process has been stopped by a signal.
825
-     *
826
-     * It always returns false on Windows.
827
-     *
828
-     * @return bool
829
-     *
830
-     * @throws LogicException In case the process is not terminated
831
-     */
832
-    public function hasBeenStopped()
833
-    {
834
-        $this->requireProcessIsTerminated(__FUNCTION__);
835
-
836
-        return $this->processInformation['stopped'];
837
-    }
838
-
839
-    /**
840
-     * Returns the number of the signal that caused the child process to stop its execution.
841
-     *
842
-     * It is only meaningful if hasBeenStopped() returns true.
843
-     *
844
-     * @return int
845
-     *
846
-     * @throws LogicException In case the process is not terminated
847
-     */
848
-    public function getStopSignal()
849
-    {
850
-        $this->requireProcessIsTerminated(__FUNCTION__);
851
-
852
-        return $this->processInformation['stopsig'];
853
-    }
854
-
855
-    /**
856
-     * Checks if the process is currently running.
857
-     *
858
-     * @return bool true if the process is currently running, false otherwise
859
-     */
860
-    public function isRunning()
861
-    {
862
-        if (self::STATUS_STARTED !== $this->status) {
863
-            return false;
864
-        }
865
-
866
-        $this->updateStatus(false);
867
-
868
-        return $this->processInformation['running'];
869
-    }
870
-
871
-    /**
872
-     * Checks if the process has been started with no regard to the current state.
873
-     *
874
-     * @return bool true if status is ready, false otherwise
875
-     */
876
-    public function isStarted()
877
-    {
878
-        return self::STATUS_READY != $this->status;
879
-    }
880
-
881
-    /**
882
-     * Checks if the process is terminated.
883
-     *
884
-     * @return bool true if process is terminated, false otherwise
885
-     */
886
-    public function isTerminated()
887
-    {
888
-        $this->updateStatus(false);
889
-
890
-        return self::STATUS_TERMINATED == $this->status;
891
-    }
892
-
893
-    /**
894
-     * Gets the process status.
895
-     *
896
-     * The status is one of: ready, started, terminated.
897
-     *
898
-     * @return string The current process status
899
-     */
900
-    public function getStatus()
901
-    {
902
-        $this->updateStatus(false);
903
-
904
-        return $this->status;
905
-    }
906
-
907
-    /**
908
-     * Stops the process.
909
-     *
910
-     * @param int|float $timeout The timeout in seconds
911
-     * @param int       $signal  A POSIX signal to send in case the process has not stop at timeout, default is SIGKILL (9)
912
-     *
913
-     * @return int|null The exit-code of the process or null if it's not running
914
-     */
915
-    public function stop(float $timeout = 10, int $signal = null)
916
-    {
917
-        $timeoutMicro = microtime(true) + $timeout;
918
-        if ($this->isRunning()) {
919
-            // given SIGTERM may not be defined and that "proc_terminate" uses the constant value and not the constant itself, we use the same here
920
-            $this->doSignal(15, false);
921
-            do {
922
-                usleep(1000);
923
-            } while ($this->isRunning() && microtime(true) < $timeoutMicro);
924
-
925
-            if ($this->isRunning()) {
926
-                // Avoid exception here: process is supposed to be running, but it might have stopped just
927
-                // after this line. In any case, let's silently discard the error, we cannot do anything.
928
-                $this->doSignal($signal ?: 9, false);
929
-            }
930
-        }
931
-
932
-        if ($this->isRunning()) {
933
-            if (isset($this->fallbackStatus['pid'])) {
934
-                unset($this->fallbackStatus['pid']);
935
-
936
-                return $this->stop(0, $signal);
937
-            }
938
-            $this->close();
939
-        }
940
-
941
-        return $this->exitcode;
942
-    }
943
-
944
-    /**
945
-     * Adds a line to the STDOUT stream.
946
-     *
947
-     * @internal
948
-     */
949
-    public function addOutput(string $line)
950
-    {
951
-        $this->lastOutputTime = microtime(true);
952
-
953
-        fseek($this->stdout, 0, \SEEK_END);
954
-        fwrite($this->stdout, $line);
955
-        fseek($this->stdout, $this->incrementalOutputOffset);
956
-    }
957
-
958
-    /**
959
-     * Adds a line to the STDERR stream.
960
-     *
961
-     * @internal
962
-     */
963
-    public function addErrorOutput(string $line)
964
-    {
965
-        $this->lastOutputTime = microtime(true);
966
-
967
-        fseek($this->stderr, 0, \SEEK_END);
968
-        fwrite($this->stderr, $line);
969
-        fseek($this->stderr, $this->incrementalErrorOutputOffset);
970
-    }
971
-
972
-    /**
973
-     * Gets the last output time in seconds.
974
-     *
975
-     * @return float|null The last output time in seconds or null if it isn't started
976
-     */
977
-    public function getLastOutputTime(): ?float
978
-    {
979
-        return $this->lastOutputTime;
980
-    }
981
-
982
-    /**
983
-     * Gets the command line to be executed.
984
-     *
985
-     * @return string The command to execute
986
-     */
987
-    public function getCommandLine()
988
-    {
989
-        return \is_array($this->commandline) ? implode(' ', array_map([$this, 'escapeArgument'], $this->commandline)) : $this->commandline;
990
-    }
991
-
992
-    /**
993
-     * Gets the process timeout (max. runtime).
994
-     *
995
-     * @return float|null The timeout in seconds or null if it's disabled
996
-     */
997
-    public function getTimeout()
998
-    {
999
-        return $this->timeout;
1000
-    }
1001
-
1002
-    /**
1003
-     * Gets the process idle timeout (max. time since last output).
1004
-     *
1005
-     * @return float|null The timeout in seconds or null if it's disabled
1006
-     */
1007
-    public function getIdleTimeout()
1008
-    {
1009
-        return $this->idleTimeout;
1010
-    }
1011
-
1012
-    /**
1013
-     * Sets the process timeout (max. runtime) in seconds.
1014
-     *
1015
-     * To disable the timeout, set this value to null.
1016
-     *
1017
-     * @return $this
1018
-     *
1019
-     * @throws InvalidArgumentException if the timeout is negative
1020
-     */
1021
-    public function setTimeout(?float $timeout)
1022
-    {
1023
-        $this->timeout = $this->validateTimeout($timeout);
1024
-
1025
-        return $this;
1026
-    }
1027
-
1028
-    /**
1029
-     * Sets the process idle timeout (max. time since last output) in seconds.
1030
-     *
1031
-     * To disable the timeout, set this value to null.
1032
-     *
1033
-     * @return $this
1034
-     *
1035
-     * @throws LogicException           if the output is disabled
1036
-     * @throws InvalidArgumentException if the timeout is negative
1037
-     */
1038
-    public function setIdleTimeout(?float $timeout)
1039
-    {
1040
-        if (null !== $timeout && $this->outputDisabled) {
1041
-            throw new LogicException('Idle timeout can not be set while the output is disabled.');
1042
-        }
1043
-
1044
-        $this->idleTimeout = $this->validateTimeout($timeout);
1045
-
1046
-        return $this;
1047
-    }
1048
-
1049
-    /**
1050
-     * Enables or disables the TTY mode.
1051
-     *
1052
-     * @return $this
1053
-     *
1054
-     * @throws RuntimeException In case the TTY mode is not supported
1055
-     */
1056
-    public function setTty(bool $tty)
1057
-    {
1058
-        if ('\\' === \DIRECTORY_SEPARATOR && $tty) {
1059
-            throw new RuntimeException('TTY mode is not supported on Windows platform.');
1060
-        }
1061
-
1062
-        if ($tty && !self::isTtySupported()) {
1063
-            throw new RuntimeException('TTY mode requires /dev/tty to be read/writable.');
1064
-        }
1065
-
1066
-        $this->tty = $tty;
1067
-
1068
-        return $this;
1069
-    }
1070
-
1071
-    /**
1072
-     * Checks if the TTY mode is enabled.
1073
-     *
1074
-     * @return bool true if the TTY mode is enabled, false otherwise
1075
-     */
1076
-    public function isTty()
1077
-    {
1078
-        return $this->tty;
1079
-    }
1080
-
1081
-    /**
1082
-     * Sets PTY mode.
1083
-     *
1084
-     * @return $this
1085
-     */
1086
-    public function setPty(bool $bool)
1087
-    {
1088
-        $this->pty = $bool;
1089
-
1090
-        return $this;
1091
-    }
1092
-
1093
-    /**
1094
-     * Returns PTY state.
1095
-     *
1096
-     * @return bool
1097
-     */
1098
-    public function isPty()
1099
-    {
1100
-        return $this->pty;
1101
-    }
1102
-
1103
-    /**
1104
-     * Gets the working directory.
1105
-     *
1106
-     * @return string|null The current working directory or null on failure
1107
-     */
1108
-    public function getWorkingDirectory()
1109
-    {
1110
-        if (null === $this->cwd) {
1111
-            // getcwd() will return false if any one of the parent directories does not have
1112
-            // the readable or search mode set, even if the current directory does
1113
-            return getcwd() ?: null;
1114
-        }
1115
-
1116
-        return $this->cwd;
1117
-    }
1118
-
1119
-    /**
1120
-     * Sets the current working directory.
1121
-     *
1122
-     * @return $this
1123
-     */
1124
-    public function setWorkingDirectory(string $cwd)
1125
-    {
1126
-        $this->cwd = $cwd;
1127
-
1128
-        return $this;
1129
-    }
1130
-
1131
-    /**
1132
-     * Gets the environment variables.
1133
-     *
1134
-     * @return array The current environment variables
1135
-     */
1136
-    public function getEnv()
1137
-    {
1138
-        return $this->env;
1139
-    }
1140
-
1141
-    /**
1142
-     * Sets the environment variables.
1143
-     *
1144
-     * Each environment variable value should be a string.
1145
-     * If it is an array, the variable is ignored.
1146
-     * If it is false or null, it will be removed when
1147
-     * env vars are otherwise inherited.
1148
-     *
1149
-     * That happens in PHP when 'argv' is registered into
1150
-     * the $_ENV array for instance.
1151
-     *
1152
-     * @param array $env The new environment variables
1153
-     *
1154
-     * @return $this
1155
-     */
1156
-    public function setEnv(array $env)
1157
-    {
1158
-        // Process can not handle env values that are arrays
1159
-        $env = array_filter($env, function ($value) {
1160
-            return !\is_array($value);
1161
-        });
1162
-
1163
-        $this->env = $env;
1164
-
1165
-        return $this;
1166
-    }
1167
-
1168
-    /**
1169
-     * Gets the Process input.
1170
-     *
1171
-     * @return resource|string|\Iterator|null The Process input
1172
-     */
1173
-    public function getInput()
1174
-    {
1175
-        return $this->input;
1176
-    }
1177
-
1178
-    /**
1179
-     * Sets the input.
1180
-     *
1181
-     * This content will be passed to the underlying process standard input.
1182
-     *
1183
-     * @param string|int|float|bool|resource|\Traversable|null $input The content
1184
-     *
1185
-     * @return $this
1186
-     *
1187
-     * @throws LogicException In case the process is running
1188
-     */
1189
-    public function setInput($input)
1190
-    {
1191
-        if ($this->isRunning()) {
1192
-            throw new LogicException('Input can not be set while the process is running.');
1193
-        }
1194
-
1195
-        $this->input = ProcessUtils::validateInput(__METHOD__, $input);
1196
-
1197
-        return $this;
1198
-    }
1199
-
1200
-    /**
1201
-     * Performs a check between the timeout definition and the time the process started.
1202
-     *
1203
-     * In case you run a background process (with the start method), you should
1204
-     * trigger this method regularly to ensure the process timeout
1205
-     *
1206
-     * @throws ProcessTimedOutException In case the timeout was reached
1207
-     */
1208
-    public function checkTimeout()
1209
-    {
1210
-        if (self::STATUS_STARTED !== $this->status) {
1211
-            return;
1212
-        }
1213
-
1214
-        if (null !== $this->timeout && $this->timeout < microtime(true) - $this->starttime) {
1215
-            $this->stop(0);
1216
-
1217
-            throw new ProcessTimedOutException($this, ProcessTimedOutException::TYPE_GENERAL);
1218
-        }
1219
-
1220
-        if (null !== $this->idleTimeout && $this->idleTimeout < microtime(true) - $this->lastOutputTime) {
1221
-            $this->stop(0);
1222
-
1223
-            throw new ProcessTimedOutException($this, ProcessTimedOutException::TYPE_IDLE);
1224
-        }
1225
-    }
1226
-
1227
-    /**
1228
-     * @throws LogicException in case process is not started
1229
-     */
1230
-    public function getStartTime(): float
1231
-    {
1232
-        if (!$this->isStarted()) {
1233
-            throw new LogicException('Start time is only available after process start.');
1234
-        }
1235
-
1236
-        return $this->starttime;
1237
-    }
1238
-
1239
-    /**
1240
-     * Defines options to pass to the underlying proc_open().
1241
-     *
1242
-     * @see https://php.net/proc_open for the options supported by PHP.
1243
-     *
1244
-     * Enabling the "create_new_console" option allows a subprocess to continue
1245
-     * to run after the main process exited, on both Windows and *nix
1246
-     */
1247
-    public function setOptions(array $options)
1248
-    {
1249
-        if ($this->isRunning()) {
1250
-            throw new RuntimeException('Setting options while the process is running is not possible.');
1251
-        }
1252
-
1253
-        $defaultOptions = $this->options;
1254
-        $existingOptions = ['blocking_pipes', 'create_process_group', 'create_new_console'];
1255
-
1256
-        foreach ($options as $key => $value) {
1257
-            if (!\in_array($key, $existingOptions)) {
1258
-                $this->options = $defaultOptions;
1259
-                throw new LogicException(sprintf('Invalid option "%s" passed to "%s()". Supported options are "%s".', $key, __METHOD__, implode('", "', $existingOptions)));
1260
-            }
1261
-            $this->options[$key] = $value;
1262
-        }
1263
-    }
1264
-
1265
-    /**
1266
-     * Returns whether TTY is supported on the current operating system.
1267
-     */
1268
-    public static function isTtySupported(): bool
1269
-    {
1270
-        static $isTtySupported;
1271
-
1272
-        if (null === $isTtySupported) {
1273
-            $isTtySupported = (bool) @proc_open('echo 1 >/dev/null', [['file', '/dev/tty', 'r'], ['file', '/dev/tty', 'w'], ['file', '/dev/tty', 'w']], $pipes);
1274
-        }
1275
-
1276
-        return $isTtySupported;
1277
-    }
1278
-
1279
-    /**
1280
-     * Returns whether PTY is supported on the current operating system.
1281
-     *
1282
-     * @return bool
1283
-     */
1284
-    public static function isPtySupported()
1285
-    {
1286
-        static $result;
1287
-
1288
-        if (null !== $result) {
1289
-            return $result;
1290
-        }
1291
-
1292
-        if ('\\' === \DIRECTORY_SEPARATOR) {
1293
-            return $result = false;
1294
-        }
1295
-
1296
-        return $result = (bool) @proc_open('echo 1 >/dev/null', [['pty'], ['pty'], ['pty']], $pipes);
1297
-    }
1298
-
1299
-    /**
1300
-     * Creates the descriptors needed by the proc_open.
1301
-     */
1302
-    private function getDescriptors(): array
1303
-    {
1304
-        if ($this->input instanceof \Iterator) {
1305
-            $this->input->rewind();
1306
-        }
1307
-        if ('\\' === \DIRECTORY_SEPARATOR) {
1308
-            $this->processPipes = new WindowsPipes($this->input, !$this->outputDisabled || $this->hasCallback);
1309
-        } else {
1310
-            $this->processPipes = new UnixPipes($this->isTty(), $this->isPty(), $this->input, !$this->outputDisabled || $this->hasCallback);
1311
-        }
1312
-
1313
-        return $this->processPipes->getDescriptors();
1314
-    }
1315
-
1316
-    /**
1317
-     * Builds up the callback used by wait().
1318
-     *
1319
-     * The callbacks adds all occurred output to the specific buffer and calls
1320
-     * the user callback (if present) with the received output.
1321
-     *
1322
-     * @param callable|null $callback The user defined PHP callback
1323
-     *
1324
-     * @return \Closure A PHP closure
1325
-     */
1326
-    protected function buildCallback(callable $callback = null)
1327
-    {
1328
-        if ($this->outputDisabled) {
1329
-            return function ($type, $data) use ($callback): bool {
1330
-                return null !== $callback && $callback($type, $data);
1331
-            };
1332
-        }
1333
-
1334
-        $out = self::OUT;
1335
-
1336
-        return function ($type, $data) use ($callback, $out): bool {
1337
-            if ($out == $type) {
1338
-                $this->addOutput($data);
1339
-            } else {
1340
-                $this->addErrorOutput($data);
1341
-            }
1342
-
1343
-            return null !== $callback && $callback($type, $data);
1344
-        };
1345
-    }
1346
-
1347
-    /**
1348
-     * Updates the status of the process, reads pipes.
1349
-     *
1350
-     * @param bool $blocking Whether to use a blocking read call
1351
-     */
1352
-    protected function updateStatus(bool $blocking)
1353
-    {
1354
-        if (self::STATUS_STARTED !== $this->status) {
1355
-            return;
1356
-        }
1357
-
1358
-        $this->processInformation = proc_get_status($this->process);
1359
-        $running = $this->processInformation['running'];
1360
-
1361
-        $this->readPipes($running && $blocking, '\\' !== \DIRECTORY_SEPARATOR || !$running);
1362
-
1363
-        if ($this->fallbackStatus && $this->isSigchildEnabled()) {
1364
-            $this->processInformation = $this->fallbackStatus + $this->processInformation;
1365
-        }
1366
-
1367
-        if (!$running) {
1368
-            $this->close();
1369
-        }
1370
-    }
1371
-
1372
-    /**
1373
-     * Returns whether PHP has been compiled with the '--enable-sigchild' option or not.
1374
-     *
1375
-     * @return bool
1376
-     */
1377
-    protected function isSigchildEnabled()
1378
-    {
1379
-        if (null !== self::$sigchild) {
1380
-            return self::$sigchild;
1381
-        }
1382
-
1383
-        if (!\function_exists('phpinfo')) {
1384
-            return self::$sigchild = false;
1385
-        }
1386
-
1387
-        ob_start();
1388
-        phpinfo(\INFO_GENERAL);
1389
-
1390
-        return self::$sigchild = str_contains(ob_get_clean(), '--enable-sigchild');
1391
-    }
1392
-
1393
-    /**
1394
-     * Reads pipes for the freshest output.
1395
-     *
1396
-     * @param string $caller   The name of the method that needs fresh outputs
1397
-     * @param bool   $blocking Whether to use blocking calls or not
1398
-     *
1399
-     * @throws LogicException in case output has been disabled or process is not started
1400
-     */
1401
-    private function readPipesForOutput(string $caller, bool $blocking = false)
1402
-    {
1403
-        if ($this->outputDisabled) {
1404
-            throw new LogicException('Output has been disabled.');
1405
-        }
1406
-
1407
-        $this->requireProcessIsStarted($caller);
1408
-
1409
-        $this->updateStatus($blocking);
1410
-    }
1411
-
1412
-    /**
1413
-     * Validates and returns the filtered timeout.
1414
-     *
1415
-     * @throws InvalidArgumentException if the given timeout is a negative number
1416
-     */
1417
-    private function validateTimeout(?float $timeout): ?float
1418
-    {
1419
-        $timeout = (float) $timeout;
1420
-
1421
-        if (0.0 === $timeout) {
1422
-            $timeout = null;
1423
-        } elseif ($timeout < 0) {
1424
-            throw new InvalidArgumentException('The timeout value must be a valid positive integer or float number.');
1425
-        }
1426
-
1427
-        return $timeout;
1428
-    }
1429
-
1430
-    /**
1431
-     * Reads pipes, executes callback.
1432
-     *
1433
-     * @param bool $blocking Whether to use blocking calls or not
1434
-     * @param bool $close    Whether to close file handles or not
1435
-     */
1436
-    private function readPipes(bool $blocking, bool $close)
1437
-    {
1438
-        $result = $this->processPipes->readAndWrite($blocking, $close);
1439
-
1440
-        $callback = $this->callback;
1441
-        foreach ($result as $type => $data) {
1442
-            if (3 !== $type) {
1443
-                $callback(self::STDOUT === $type ? self::OUT : self::ERR, $data);
1444
-            } elseif (!isset($this->fallbackStatus['signaled'])) {
1445
-                $this->fallbackStatus['exitcode'] = (int) $data;
1446
-            }
1447
-        }
1448
-    }
1449
-
1450
-    /**
1451
-     * Closes process resource, closes file handles, sets the exitcode.
1452
-     *
1453
-     * @return int The exitcode
1454
-     */
1455
-    private function close(): int
1456
-    {
1457
-        $this->processPipes->close();
1458
-        if (\is_resource($this->process)) {
1459
-            proc_close($this->process);
1460
-        }
1461
-        $this->exitcode = $this->processInformation['exitcode'];
1462
-        $this->status = self::STATUS_TERMINATED;
1463
-
1464
-        if (-1 === $this->exitcode) {
1465
-            if ($this->processInformation['signaled'] && 0 < $this->processInformation['termsig']) {
1466
-                // if process has been signaled, no exitcode but a valid termsig, apply Unix convention
1467
-                $this->exitcode = 128 + $this->processInformation['termsig'];
1468
-            } elseif ($this->isSigchildEnabled()) {
1469
-                $this->processInformation['signaled'] = true;
1470
-                $this->processInformation['termsig'] = -1;
1471
-            }
1472
-        }
1473
-
1474
-        // Free memory from self-reference callback created by buildCallback
1475
-        // Doing so in other contexts like __destruct or by garbage collector is ineffective
1476
-        // Now pipes are closed, so the callback is no longer necessary
1477
-        $this->callback = null;
1478
-
1479
-        return $this->exitcode;
1480
-    }
1481
-
1482
-    /**
1483
-     * Resets data related to the latest run of the process.
1484
-     */
1485
-    private function resetProcessData()
1486
-    {
1487
-        $this->starttime = null;
1488
-        $this->callback = null;
1489
-        $this->exitcode = null;
1490
-        $this->fallbackStatus = [];
1491
-        $this->processInformation = null;
1492
-        $this->stdout = fopen('php://temp/maxmemory:'.(1024 * 1024), 'w+');
1493
-        $this->stderr = fopen('php://temp/maxmemory:'.(1024 * 1024), 'w+');
1494
-        $this->process = null;
1495
-        $this->latestSignal = null;
1496
-        $this->status = self::STATUS_READY;
1497
-        $this->incrementalOutputOffset = 0;
1498
-        $this->incrementalErrorOutputOffset = 0;
1499
-    }
1500
-
1501
-    /**
1502
-     * Sends a POSIX signal to the process.
1503
-     *
1504
-     * @param int  $signal         A valid POSIX signal (see https://php.net/pcntl.constants)
1505
-     * @param bool $throwException Whether to throw exception in case signal failed
1506
-     *
1507
-     * @return bool True if the signal was sent successfully, false otherwise
1508
-     *
1509
-     * @throws LogicException   In case the process is not running
1510
-     * @throws RuntimeException In case --enable-sigchild is activated and the process can't be killed
1511
-     * @throws RuntimeException In case of failure
1512
-     */
1513
-    private function doSignal(int $signal, bool $throwException): bool
1514
-    {
1515
-        if (null === $pid = $this->getPid()) {
1516
-            if ($throwException) {
1517
-                throw new LogicException('Can not send signal on a non running process.');
1518
-            }
1519
-
1520
-            return false;
1521
-        }
1522
-
1523
-        if ('\\' === \DIRECTORY_SEPARATOR) {
1524
-            exec(sprintf('taskkill /F /T /PID %d 2>&1', $pid), $output, $exitCode);
1525
-            if ($exitCode && $this->isRunning()) {
1526
-                if ($throwException) {
1527
-                    throw new RuntimeException(sprintf('Unable to kill the process (%s).', implode(' ', $output)));
1528
-                }
1529
-
1530
-                return false;
1531
-            }
1532
-        } else {
1533
-            if (!$this->isSigchildEnabled()) {
1534
-                $ok = @proc_terminate($this->process, $signal);
1535
-            } elseif (\function_exists('posix_kill')) {
1536
-                $ok = @posix_kill($pid, $signal);
1537
-            } elseif ($ok = proc_open(sprintf('kill -%d %d', $signal, $pid), [2 => ['pipe', 'w']], $pipes)) {
1538
-                $ok = false === fgets($pipes[2]);
1539
-            }
1540
-            if (!$ok) {
1541
-                if ($throwException) {
1542
-                    throw new RuntimeException(sprintf('Error while sending signal "%s".', $signal));
1543
-                }
1544
-
1545
-                return false;
1546
-            }
1547
-        }
1548
-
1549
-        $this->latestSignal = $signal;
1550
-        $this->fallbackStatus['signaled'] = true;
1551
-        $this->fallbackStatus['exitcode'] = -1;
1552
-        $this->fallbackStatus['termsig'] = $this->latestSignal;
1553
-
1554
-        return true;
1555
-    }
1556
-
1557
-    private function prepareWindowsCommandLine(string $cmd, array &$env): string
1558
-    {
1559
-        $uid = uniqid('', true);
1560
-        $varCount = 0;
1561
-        $varCache = [];
1562
-        $cmd = preg_replace_callback(
1563
-            '/"(?:(
33
+	public const ERR = 'err';
34
+	public const OUT = 'out';
35
+
36
+	public const STATUS_READY = 'ready';
37
+	public const STATUS_STARTED = 'started';
38
+	public const STATUS_TERMINATED = 'terminated';
39
+
40
+	public const STDIN = 0;
41
+	public const STDOUT = 1;
42
+	public const STDERR = 2;
43
+
44
+	// Timeout Precision in seconds.
45
+	public const TIMEOUT_PRECISION = 0.2;
46
+
47
+	public const ITER_NON_BLOCKING = 1; // By default, iterating over outputs is a blocking call, use this flag to make it non-blocking
48
+	public const ITER_KEEP_OUTPUT = 2;  // By default, outputs are cleared while iterating, use this flag to keep them in memory
49
+	public const ITER_SKIP_OUT = 4;     // Use this flag to skip STDOUT while iterating
50
+	public const ITER_SKIP_ERR = 8;     // Use this flag to skip STDERR while iterating
51
+
52
+	private $callback;
53
+	private $hasCallback = false;
54
+	private $commandline;
55
+	private $cwd;
56
+	private $env;
57
+	private $input;
58
+	private $starttime;
59
+	private $lastOutputTime;
60
+	private $timeout;
61
+	private $idleTimeout;
62
+	private $exitcode;
63
+	private $fallbackStatus = [];
64
+	private $processInformation;
65
+	private $outputDisabled = false;
66
+	private $stdout;
67
+	private $stderr;
68
+	private $process;
69
+	private $status = self::STATUS_READY;
70
+	private $incrementalOutputOffset = 0;
71
+	private $incrementalErrorOutputOffset = 0;
72
+	private $tty = false;
73
+	private $pty;
74
+	private $options = ['suppress_errors' => true, 'bypass_shell' => true];
75
+
76
+	private $useFileHandles = false;
77
+	/** @var PipesInterface */
78
+	private $processPipes;
79
+
80
+	private $latestSignal;
81
+
82
+	private static $sigchild;
83
+
84
+	/**
85
+	 * Exit codes translation table.
86
+	 *
87
+	 * User-defined errors must use exit codes in the 64-113 range.
88
+	 */
89
+	public static $exitCodes = [
90
+		0 => 'OK',
91
+		1 => 'General error',
92
+		2 => 'Misuse of shell builtins',
93
+
94
+		126 => 'Invoked command cannot execute',
95
+		127 => 'Command not found',
96
+		128 => 'Invalid exit argument',
97
+
98
+		// signals
99
+		129 => 'Hangup',
100
+		130 => 'Interrupt',
101
+		131 => 'Quit and dump core',
102
+		132 => 'Illegal instruction',
103
+		133 => 'Trace/breakpoint trap',
104
+		134 => 'Process aborted',
105
+		135 => 'Bus error: "access to undefined portion of memory object"',
106
+		136 => 'Floating point exception: "erroneous arithmetic operation"',
107
+		137 => 'Kill (terminate immediately)',
108
+		138 => 'User-defined 1',
109
+		139 => 'Segmentation violation',
110
+		140 => 'User-defined 2',
111
+		141 => 'Write to pipe with no one reading',
112
+		142 => 'Signal raised by alarm',
113
+		143 => 'Termination (request to terminate)',
114
+		// 144 - not defined
115
+		145 => 'Child process terminated, stopped (or continued*)',
116
+		146 => 'Continue if stopped',
117
+		147 => 'Stop executing temporarily',
118
+		148 => 'Terminal stop signal',
119
+		149 => 'Background process attempting to read from tty ("in")',
120
+		150 => 'Background process attempting to write to tty ("out")',
121
+		151 => 'Urgent data available on socket',
122
+		152 => 'CPU time limit exceeded',
123
+		153 => 'File size limit exceeded',
124
+		154 => 'Signal raised by timer counting virtual time: "virtual timer expired"',
125
+		155 => 'Profiling timer expired',
126
+		// 156 - not defined
127
+		157 => 'Pollable event',
128
+		// 158 - not defined
129
+		159 => 'Bad syscall',
130
+	];
131
+
132
+	/**
133
+	 * @param array          $command The command to run and its arguments listed as separate entries
134
+	 * @param string|null    $cwd     The working directory or null to use the working dir of the current PHP process
135
+	 * @param array|null     $env     The environment variables or null to use the same environment as the current PHP process
136
+	 * @param mixed          $input   The input as stream resource, scalar or \Traversable, or null for no input
137
+	 * @param int|float|null $timeout The timeout in seconds or null to disable
138
+	 *
139
+	 * @throws LogicException When proc_open is not installed
140
+	 */
141
+	public function __construct(array $command, string $cwd = null, array $env = null, $input = null, ?float $timeout = 60)
142
+	{
143
+		if (!\function_exists('proc_open')) {
144
+			throw new LogicException('The Process class relies on proc_open, which is not available on your PHP installation.');
145
+		}
146
+
147
+		$this->commandline = $command;
148
+		$this->cwd = $cwd;
149
+
150
+		// on Windows, if the cwd changed via chdir(), proc_open defaults to the dir where PHP was started
151
+		// on Gnu/Linux, PHP builds with --enable-maintainer-zts are also affected
152
+		// @see : https://bugs.php.net/51800
153
+		// @see : https://bugs.php.net/50524
154
+		if (null === $this->cwd && (\defined('ZEND_THREAD_SAFE') || '\\' === \DIRECTORY_SEPARATOR)) {
155
+			$this->cwd = getcwd();
156
+		}
157
+		if (null !== $env) {
158
+			$this->setEnv($env);
159
+		}
160
+
161
+		$this->setInput($input);
162
+		$this->setTimeout($timeout);
163
+		$this->useFileHandles = '\\' === \DIRECTORY_SEPARATOR;
164
+		$this->pty = false;
165
+	}
166
+
167
+	/**
168
+	 * Creates a Process instance as a command-line to be run in a shell wrapper.
169
+	 *
170
+	 * Command-lines are parsed by the shell of your OS (/bin/sh on Unix-like, cmd.exe on Windows.)
171
+	 * This allows using e.g. pipes or conditional execution. In this mode, signals are sent to the
172
+	 * shell wrapper and not to your commands.
173
+	 *
174
+	 * In order to inject dynamic values into command-lines, we strongly recommend using placeholders.
175
+	 * This will save escaping values, which is not portable nor secure anyway:
176
+	 *
177
+	 *   $process = Process::fromShellCommandline('my_command "$MY_VAR"');
178
+	 *   $process->run(null, ['MY_VAR' => $theValue]);
179
+	 *
180
+	 * @param string         $command The command line to pass to the shell of the OS
181
+	 * @param string|null    $cwd     The working directory or null to use the working dir of the current PHP process
182
+	 * @param array|null     $env     The environment variables or null to use the same environment as the current PHP process
183
+	 * @param mixed          $input   The input as stream resource, scalar or \Traversable, or null for no input
184
+	 * @param int|float|null $timeout The timeout in seconds or null to disable
185
+	 *
186
+	 * @return static
187
+	 *
188
+	 * @throws LogicException When proc_open is not installed
189
+	 */
190
+	public static function fromShellCommandline(string $command, string $cwd = null, array $env = null, $input = null, ?float $timeout = 60)
191
+	{
192
+		$process = new static([], $cwd, $env, $input, $timeout);
193
+		$process->commandline = $command;
194
+
195
+		return $process;
196
+	}
197
+
198
+	/**
199
+	 * @return array
200
+	 */
201
+	public function __sleep()
202
+	{
203
+		throw new \BadMethodCallException('Cannot serialize '.__CLASS__);
204
+	}
205
+
206
+	public function __wakeup()
207
+	{
208
+		throw new \BadMethodCallException('Cannot unserialize '.__CLASS__);
209
+	}
210
+
211
+	public function __destruct()
212
+	{
213
+		if ($this->options['create_new_console'] ?? false) {
214
+			$this->processPipes->close();
215
+		} else {
216
+			$this->stop(0);
217
+		}
218
+	}
219
+
220
+	public function __clone()
221
+	{
222
+		$this->resetProcessData();
223
+	}
224
+
225
+	/**
226
+	 * Runs the process.
227
+	 *
228
+	 * The callback receives the type of output (out or err) and
229
+	 * some bytes from the output in real-time. It allows to have feedback
230
+	 * from the independent process during execution.
231
+	 *
232
+	 * The STDOUT and STDERR are also available after the process is finished
233
+	 * via the getOutput() and getErrorOutput() methods.
234
+	 *
235
+	 * @param callable|null $callback A PHP callback to run whenever there is some
236
+	 *                                output available on STDOUT or STDERR
237
+	 *
238
+	 * @return int The exit status code
239
+	 *
240
+	 * @throws RuntimeException         When process can't be launched
241
+	 * @throws RuntimeException         When process is already running
242
+	 * @throws ProcessTimedOutException When process timed out
243
+	 * @throws ProcessSignaledException When process stopped after receiving signal
244
+	 * @throws LogicException           In case a callback is provided and output has been disabled
245
+	 *
246
+	 * @final
247
+	 */
248
+	public function run(callable $callback = null, array $env = []): int
249
+	{
250
+		$this->start($callback, $env);
251
+
252
+		return $this->wait();
253
+	}
254
+
255
+	/**
256
+	 * Runs the process.
257
+	 *
258
+	 * This is identical to run() except that an exception is thrown if the process
259
+	 * exits with a non-zero exit code.
260
+	 *
261
+	 * @return $this
262
+	 *
263
+	 * @throws ProcessFailedException if the process didn't terminate successfully
264
+	 *
265
+	 * @final
266
+	 */
267
+	public function mustRun(callable $callback = null, array $env = []): self
268
+	{
269
+		if (0 !== $this->run($callback, $env)) {
270
+			throw new ProcessFailedException($this);
271
+		}
272
+
273
+		return $this;
274
+	}
275
+
276
+	/**
277
+	 * Starts the process and returns after writing the input to STDIN.
278
+	 *
279
+	 * This method blocks until all STDIN data is sent to the process then it
280
+	 * returns while the process runs in the background.
281
+	 *
282
+	 * The termination of the process can be awaited with wait().
283
+	 *
284
+	 * The callback receives the type of output (out or err) and some bytes from
285
+	 * the output in real-time while writing the standard input to the process.
286
+	 * It allows to have feedback from the independent process during execution.
287
+	 *
288
+	 * @param callable|null $callback A PHP callback to run whenever there is some
289
+	 *                                output available on STDOUT or STDERR
290
+	 *
291
+	 * @throws RuntimeException When process can't be launched
292
+	 * @throws RuntimeException When process is already running
293
+	 * @throws LogicException   In case a callback is provided and output has been disabled
294
+	 */
295
+	public function start(callable $callback = null, array $env = [])
296
+	{
297
+		if ($this->isRunning()) {
298
+			throw new RuntimeException('Process is already running.');
299
+		}
300
+
301
+		$this->resetProcessData();
302
+		$this->starttime = $this->lastOutputTime = microtime(true);
303
+		$this->callback = $this->buildCallback($callback);
304
+		$this->hasCallback = null !== $callback;
305
+		$descriptors = $this->getDescriptors();
306
+
307
+		if ($this->env) {
308
+			$env += $this->env;
309
+		}
310
+
311
+		$env += $this->getDefaultEnv();
312
+
313
+		if (\is_array($commandline = $this->commandline)) {
314
+			$commandline = implode(' ', array_map([$this, 'escapeArgument'], $commandline));
315
+
316
+			if ('\\' !== \DIRECTORY_SEPARATOR) {
317
+				// exec is mandatory to deal with sending a signal to the process
318
+				$commandline = 'exec '.$commandline;
319
+			}
320
+		} else {
321
+			$commandline = $this->replacePlaceholders($commandline, $env);
322
+		}
323
+
324
+		if ('\\' === \DIRECTORY_SEPARATOR) {
325
+			$commandline = $this->prepareWindowsCommandLine($commandline, $env);
326
+		} elseif (!$this->useFileHandles && $this->isSigchildEnabled()) {
327
+			// last exit code is output on the fourth pipe and caught to work around --enable-sigchild
328
+			$descriptors[3] = ['pipe', 'w'];
329
+
330
+			// See https://unix.stackexchange.com/questions/71205/background-process-pipe-input
331
+			$commandline = '{ ('.$commandline.') <&3 3<&- 3>/dev/null & } 3<&0;';
332
+			$commandline .= 'pid=$!; echo $pid >&3; wait $pid; code=$?; echo $code >&3; exit $code';
333
+
334
+			// Workaround for the bug, when PTS functionality is enabled.
335
+			// @see : https://bugs.php.net/69442
336
+			$ptsWorkaround = fopen(__FILE__, 'r');
337
+		}
338
+
339
+		$envPairs = [];
340
+		foreach ($env as $k => $v) {
341
+			if (false !== $v) {
342
+				$envPairs[] = $k.'='.$v;
343
+			}
344
+		}
345
+
346
+		if (!is_dir($this->cwd)) {
347
+			throw new RuntimeException(sprintf('The provided cwd "%s" does not exist.', $this->cwd));
348
+		}
349
+
350
+		$this->process = @proc_open($commandline, $descriptors, $this->processPipes->pipes, $this->cwd, $envPairs, $this->options);
351
+
352
+		if (!\is_resource($this->process)) {
353
+			throw new RuntimeException('Unable to launch a new process.');
354
+		}
355
+		$this->status = self::STATUS_STARTED;
356
+
357
+		if (isset($descriptors[3])) {
358
+			$this->fallbackStatus['pid'] = (int) fgets($this->processPipes->pipes[3]);
359
+		}
360
+
361
+		if ($this->tty) {
362
+			return;
363
+		}
364
+
365
+		$this->updateStatus(false);
366
+		$this->checkTimeout();
367
+	}
368
+
369
+	/**
370
+	 * Restarts the process.
371
+	 *
372
+	 * Be warned that the process is cloned before being started.
373
+	 *
374
+	 * @param callable|null $callback A PHP callback to run whenever there is some
375
+	 *                                output available on STDOUT or STDERR
376
+	 *
377
+	 * @return static
378
+	 *
379
+	 * @throws RuntimeException When process can't be launched
380
+	 * @throws RuntimeException When process is already running
381
+	 *
382
+	 * @see start()
383
+	 *
384
+	 * @final
385
+	 */
386
+	public function restart(callable $callback = null, array $env = []): self
387
+	{
388
+		if ($this->isRunning()) {
389
+			throw new RuntimeException('Process is already running.');
390
+		}
391
+
392
+		$process = clone $this;
393
+		$process->start($callback, $env);
394
+
395
+		return $process;
396
+	}
397
+
398
+	/**
399
+	 * Waits for the process to terminate.
400
+	 *
401
+	 * The callback receives the type of output (out or err) and some bytes
402
+	 * from the output in real-time while writing the standard input to the process.
403
+	 * It allows to have feedback from the independent process during execution.
404
+	 *
405
+	 * @param callable|null $callback A valid PHP callback
406
+	 *
407
+	 * @return int The exitcode of the process
408
+	 *
409
+	 * @throws ProcessTimedOutException When process timed out
410
+	 * @throws ProcessSignaledException When process stopped after receiving signal
411
+	 * @throws LogicException           When process is not yet started
412
+	 */
413
+	public function wait(callable $callback = null)
414
+	{
415
+		$this->requireProcessIsStarted(__FUNCTION__);
416
+
417
+		$this->updateStatus(false);
418
+
419
+		if (null !== $callback) {
420
+			if (!$this->processPipes->haveReadSupport()) {
421
+				$this->stop(0);
422
+				throw new LogicException('Pass the callback to the "Process::start" method or call enableOutput to use a callback with "Process::wait".');
423
+			}
424
+			$this->callback = $this->buildCallback($callback);
425
+		}
426
+
427
+		do {
428
+			$this->checkTimeout();
429
+			$running = '\\' === \DIRECTORY_SEPARATOR ? $this->isRunning() : $this->processPipes->areOpen();
430
+			$this->readPipes($running, '\\' !== \DIRECTORY_SEPARATOR || !$running);
431
+		} while ($running);
432
+
433
+		while ($this->isRunning()) {
434
+			$this->checkTimeout();
435
+			usleep(1000);
436
+		}
437
+
438
+		if ($this->processInformation['signaled'] && $this->processInformation['termsig'] !== $this->latestSignal) {
439
+			throw new ProcessSignaledException($this);
440
+		}
441
+
442
+		return $this->exitcode;
443
+	}
444
+
445
+	/**
446
+	 * Waits until the callback returns true.
447
+	 *
448
+	 * The callback receives the type of output (out or err) and some bytes
449
+	 * from the output in real-time while writing the standard input to the process.
450
+	 * It allows to have feedback from the independent process during execution.
451
+	 *
452
+	 * @throws RuntimeException         When process timed out
453
+	 * @throws LogicException           When process is not yet started
454
+	 * @throws ProcessTimedOutException In case the timeout was reached
455
+	 */
456
+	public function waitUntil(callable $callback): bool
457
+	{
458
+		$this->requireProcessIsStarted(__FUNCTION__);
459
+		$this->updateStatus(false);
460
+
461
+		if (!$this->processPipes->haveReadSupport()) {
462
+			$this->stop(0);
463
+			throw new LogicException('Pass the callback to the "Process::start" method or call enableOutput to use a callback with "Process::waitUntil".');
464
+		}
465
+		$callback = $this->buildCallback($callback);
466
+
467
+		$ready = false;
468
+		while (true) {
469
+			$this->checkTimeout();
470
+			$running = '\\' === \DIRECTORY_SEPARATOR ? $this->isRunning() : $this->processPipes->areOpen();
471
+			$output = $this->processPipes->readAndWrite($running, '\\' !== \DIRECTORY_SEPARATOR || !$running);
472
+
473
+			foreach ($output as $type => $data) {
474
+				if (3 !== $type) {
475
+					$ready = $callback(self::STDOUT === $type ? self::OUT : self::ERR, $data) || $ready;
476
+				} elseif (!isset($this->fallbackStatus['signaled'])) {
477
+					$this->fallbackStatus['exitcode'] = (int) $data;
478
+				}
479
+			}
480
+			if ($ready) {
481
+				return true;
482
+			}
483
+			if (!$running) {
484
+				return false;
485
+			}
486
+
487
+			usleep(1000);
488
+		}
489
+	}
490
+
491
+	/**
492
+	 * Returns the Pid (process identifier), if applicable.
493
+	 *
494
+	 * @return int|null The process id if running, null otherwise
495
+	 */
496
+	public function getPid()
497
+	{
498
+		return $this->isRunning() ? $this->processInformation['pid'] : null;
499
+	}
500
+
501
+	/**
502
+	 * Sends a POSIX signal to the process.
503
+	 *
504
+	 * @param int $signal A valid POSIX signal (see https://php.net/pcntl.constants)
505
+	 *
506
+	 * @return $this
507
+	 *
508
+	 * @throws LogicException   In case the process is not running
509
+	 * @throws RuntimeException In case --enable-sigchild is activated and the process can't be killed
510
+	 * @throws RuntimeException In case of failure
511
+	 */
512
+	public function signal(int $signal)
513
+	{
514
+		$this->doSignal($signal, true);
515
+
516
+		return $this;
517
+	}
518
+
519
+	/**
520
+	 * Disables fetching output and error output from the underlying process.
521
+	 *
522
+	 * @return $this
523
+	 *
524
+	 * @throws RuntimeException In case the process is already running
525
+	 * @throws LogicException   if an idle timeout is set
526
+	 */
527
+	public function disableOutput()
528
+	{
529
+		if ($this->isRunning()) {
530
+			throw new RuntimeException('Disabling output while the process is running is not possible.');
531
+		}
532
+		if (null !== $this->idleTimeout) {
533
+			throw new LogicException('Output can not be disabled while an idle timeout is set.');
534
+		}
535
+
536
+		$this->outputDisabled = true;
537
+
538
+		return $this;
539
+	}
540
+
541
+	/**
542
+	 * Enables fetching output and error output from the underlying process.
543
+	 *
544
+	 * @return $this
545
+	 *
546
+	 * @throws RuntimeException In case the process is already running
547
+	 */
548
+	public function enableOutput()
549
+	{
550
+		if ($this->isRunning()) {
551
+			throw new RuntimeException('Enabling output while the process is running is not possible.');
552
+		}
553
+
554
+		$this->outputDisabled = false;
555
+
556
+		return $this;
557
+	}
558
+
559
+	/**
560
+	 * Returns true in case the output is disabled, false otherwise.
561
+	 *
562
+	 * @return bool
563
+	 */
564
+	public function isOutputDisabled()
565
+	{
566
+		return $this->outputDisabled;
567
+	}
568
+
569
+	/**
570
+	 * Returns the current output of the process (STDOUT).
571
+	 *
572
+	 * @return string The process output
573
+	 *
574
+	 * @throws LogicException in case the output has been disabled
575
+	 * @throws LogicException In case the process is not started
576
+	 */
577
+	public function getOutput()
578
+	{
579
+		$this->readPipesForOutput(__FUNCTION__);
580
+
581
+		if (false === $ret = stream_get_contents($this->stdout, -1, 0)) {
582
+			return '';
583
+		}
584
+
585
+		return $ret;
586
+	}
587
+
588
+	/**
589
+	 * Returns the output incrementally.
590
+	 *
591
+	 * In comparison with the getOutput method which always return the whole
592
+	 * output, this one returns the new output since the last call.
593
+	 *
594
+	 * @return string The process output since the last call
595
+	 *
596
+	 * @throws LogicException in case the output has been disabled
597
+	 * @throws LogicException In case the process is not started
598
+	 */
599
+	public function getIncrementalOutput()
600
+	{
601
+		$this->readPipesForOutput(__FUNCTION__);
602
+
603
+		$latest = stream_get_contents($this->stdout, -1, $this->incrementalOutputOffset);
604
+		$this->incrementalOutputOffset = ftell($this->stdout);
605
+
606
+		if (false === $latest) {
607
+			return '';
608
+		}
609
+
610
+		return $latest;
611
+	}
612
+
613
+	/**
614
+	 * Returns an iterator to the output of the process, with the output type as keys (Process::OUT/ERR).
615
+	 *
616
+	 * @param int $flags A bit field of Process::ITER_* flags
617
+	 *
618
+	 * @throws LogicException in case the output has been disabled
619
+	 * @throws LogicException In case the process is not started
620
+	 *
621
+	 * @return \Generator
622
+	 */
623
+	#[\ReturnTypeWillChange]
624
+	public function getIterator(int $flags = 0)
625
+	{
626
+		$this->readPipesForOutput(__FUNCTION__, false);
627
+
628
+		$clearOutput = !(self::ITER_KEEP_OUTPUT & $flags);
629
+		$blocking = !(self::ITER_NON_BLOCKING & $flags);
630
+		$yieldOut = !(self::ITER_SKIP_OUT & $flags);
631
+		$yieldErr = !(self::ITER_SKIP_ERR & $flags);
632
+
633
+		while (null !== $this->callback || ($yieldOut && !feof($this->stdout)) || ($yieldErr && !feof($this->stderr))) {
634
+			if ($yieldOut) {
635
+				$out = stream_get_contents($this->stdout, -1, $this->incrementalOutputOffset);
636
+
637
+				if (isset($out[0])) {
638
+					if ($clearOutput) {
639
+						$this->clearOutput();
640
+					} else {
641
+						$this->incrementalOutputOffset = ftell($this->stdout);
642
+					}
643
+
644
+					yield self::OUT => $out;
645
+				}
646
+			}
647
+
648
+			if ($yieldErr) {
649
+				$err = stream_get_contents($this->stderr, -1, $this->incrementalErrorOutputOffset);
650
+
651
+				if (isset($err[0])) {
652
+					if ($clearOutput) {
653
+						$this->clearErrorOutput();
654
+					} else {
655
+						$this->incrementalErrorOutputOffset = ftell($this->stderr);
656
+					}
657
+
658
+					yield self::ERR => $err;
659
+				}
660
+			}
661
+
662
+			if (!$blocking && !isset($out[0]) && !isset($err[0])) {
663
+				yield self::OUT => '';
664
+			}
665
+
666
+			$this->checkTimeout();
667
+			$this->readPipesForOutput(__FUNCTION__, $blocking);
668
+		}
669
+	}
670
+
671
+	/**
672
+	 * Clears the process output.
673
+	 *
674
+	 * @return $this
675
+	 */
676
+	public function clearOutput()
677
+	{
678
+		ftruncate($this->stdout, 0);
679
+		fseek($this->stdout, 0);
680
+		$this->incrementalOutputOffset = 0;
681
+
682
+		return $this;
683
+	}
684
+
685
+	/**
686
+	 * Returns the current error output of the process (STDERR).
687
+	 *
688
+	 * @return string The process error output
689
+	 *
690
+	 * @throws LogicException in case the output has been disabled
691
+	 * @throws LogicException In case the process is not started
692
+	 */
693
+	public function getErrorOutput()
694
+	{
695
+		$this->readPipesForOutput(__FUNCTION__);
696
+
697
+		if (false === $ret = stream_get_contents($this->stderr, -1, 0)) {
698
+			return '';
699
+		}
700
+
701
+		return $ret;
702
+	}
703
+
704
+	/**
705
+	 * Returns the errorOutput incrementally.
706
+	 *
707
+	 * In comparison with the getErrorOutput method which always return the
708
+	 * whole error output, this one returns the new error output since the last
709
+	 * call.
710
+	 *
711
+	 * @return string The process error output since the last call
712
+	 *
713
+	 * @throws LogicException in case the output has been disabled
714
+	 * @throws LogicException In case the process is not started
715
+	 */
716
+	public function getIncrementalErrorOutput()
717
+	{
718
+		$this->readPipesForOutput(__FUNCTION__);
719
+
720
+		$latest = stream_get_contents($this->stderr, -1, $this->incrementalErrorOutputOffset);
721
+		$this->incrementalErrorOutputOffset = ftell($this->stderr);
722
+
723
+		if (false === $latest) {
724
+			return '';
725
+		}
726
+
727
+		return $latest;
728
+	}
729
+
730
+	/**
731
+	 * Clears the process output.
732
+	 *
733
+	 * @return $this
734
+	 */
735
+	public function clearErrorOutput()
736
+	{
737
+		ftruncate($this->stderr, 0);
738
+		fseek($this->stderr, 0);
739
+		$this->incrementalErrorOutputOffset = 0;
740
+
741
+		return $this;
742
+	}
743
+
744
+	/**
745
+	 * Returns the exit code returned by the process.
746
+	 *
747
+	 * @return int|null The exit status code, null if the Process is not terminated
748
+	 */
749
+	public function getExitCode()
750
+	{
751
+		$this->updateStatus(false);
752
+
753
+		return $this->exitcode;
754
+	}
755
+
756
+	/**
757
+	 * Returns a string representation for the exit code returned by the process.
758
+	 *
759
+	 * This method relies on the Unix exit code status standardization
760
+	 * and might not be relevant for other operating systems.
761
+	 *
762
+	 * @return string|null A string representation for the exit status code, null if the Process is not terminated
763
+	 *
764
+	 * @see http://tldp.org/LDP/abs/html/exitcodes.html
765
+	 * @see http://en.wikipedia.org/wiki/Unix_signal
766
+	 */
767
+	public function getExitCodeText()
768
+	{
769
+		if (null === $exitcode = $this->getExitCode()) {
770
+			return null;
771
+		}
772
+
773
+		return self::$exitCodes[$exitcode] ?? 'Unknown error';
774
+	}
775
+
776
+	/**
777
+	 * Checks if the process ended successfully.
778
+	 *
779
+	 * @return bool true if the process ended successfully, false otherwise
780
+	 */
781
+	public function isSuccessful()
782
+	{
783
+		return 0 === $this->getExitCode();
784
+	}
785
+
786
+	/**
787
+	 * Returns true if the child process has been terminated by an uncaught signal.
788
+	 *
789
+	 * It always returns false on Windows.
790
+	 *
791
+	 * @return bool
792
+	 *
793
+	 * @throws LogicException In case the process is not terminated
794
+	 */
795
+	public function hasBeenSignaled()
796
+	{
797
+		$this->requireProcessIsTerminated(__FUNCTION__);
798
+
799
+		return $this->processInformation['signaled'];
800
+	}
801
+
802
+	/**
803
+	 * Returns the number of the signal that caused the child process to terminate its execution.
804
+	 *
805
+	 * It is only meaningful if hasBeenSignaled() returns true.
806
+	 *
807
+	 * @return int
808
+	 *
809
+	 * @throws RuntimeException In case --enable-sigchild is activated
810
+	 * @throws LogicException   In case the process is not terminated
811
+	 */
812
+	public function getTermSignal()
813
+	{
814
+		$this->requireProcessIsTerminated(__FUNCTION__);
815
+
816
+		if ($this->isSigchildEnabled() && -1 === $this->processInformation['termsig']) {
817
+			throw new RuntimeException('This PHP has been compiled with --enable-sigchild. Term signal can not be retrieved.');
818
+		}
819
+
820
+		return $this->processInformation['termsig'];
821
+	}
822
+
823
+	/**
824
+	 * Returns true if the child process has been stopped by a signal.
825
+	 *
826
+	 * It always returns false on Windows.
827
+	 *
828
+	 * @return bool
829
+	 *
830
+	 * @throws LogicException In case the process is not terminated
831
+	 */
832
+	public function hasBeenStopped()
833
+	{
834
+		$this->requireProcessIsTerminated(__FUNCTION__);
835
+
836
+		return $this->processInformation['stopped'];
837
+	}
838
+
839
+	/**
840
+	 * Returns the number of the signal that caused the child process to stop its execution.
841
+	 *
842
+	 * It is only meaningful if hasBeenStopped() returns true.
843
+	 *
844
+	 * @return int
845
+	 *
846
+	 * @throws LogicException In case the process is not terminated
847
+	 */
848
+	public function getStopSignal()
849
+	{
850
+		$this->requireProcessIsTerminated(__FUNCTION__);
851
+
852
+		return $this->processInformation['stopsig'];
853
+	}
854
+
855
+	/**
856
+	 * Checks if the process is currently running.
857
+	 *
858
+	 * @return bool true if the process is currently running, false otherwise
859
+	 */
860
+	public function isRunning()
861
+	{
862
+		if (self::STATUS_STARTED !== $this->status) {
863
+			return false;
864
+		}
865
+
866
+		$this->updateStatus(false);
867
+
868
+		return $this->processInformation['running'];
869
+	}
870
+
871
+	/**
872
+	 * Checks if the process has been started with no regard to the current state.
873
+	 *
874
+	 * @return bool true if status is ready, false otherwise
875
+	 */
876
+	public function isStarted()
877
+	{
878
+		return self::STATUS_READY != $this->status;
879
+	}
880
+
881
+	/**
882
+	 * Checks if the process is terminated.
883
+	 *
884
+	 * @return bool true if process is terminated, false otherwise
885
+	 */
886
+	public function isTerminated()
887
+	{
888
+		$this->updateStatus(false);
889
+
890
+		return self::STATUS_TERMINATED == $this->status;
891
+	}
892
+
893
+	/**
894
+	 * Gets the process status.
895
+	 *
896
+	 * The status is one of: ready, started, terminated.
897
+	 *
898
+	 * @return string The current process status
899
+	 */
900
+	public function getStatus()
901
+	{
902
+		$this->updateStatus(false);
903
+
904
+		return $this->status;
905
+	}
906
+
907
+	/**
908
+	 * Stops the process.
909
+	 *
910
+	 * @param int|float $timeout The timeout in seconds
911
+	 * @param int       $signal  A POSIX signal to send in case the process has not stop at timeout, default is SIGKILL (9)
912
+	 *
913
+	 * @return int|null The exit-code of the process or null if it's not running
914
+	 */
915
+	public function stop(float $timeout = 10, int $signal = null)
916
+	{
917
+		$timeoutMicro = microtime(true) + $timeout;
918
+		if ($this->isRunning()) {
919
+			// given SIGTERM may not be defined and that "proc_terminate" uses the constant value and not the constant itself, we use the same here
920
+			$this->doSignal(15, false);
921
+			do {
922
+				usleep(1000);
923
+			} while ($this->isRunning() && microtime(true) < $timeoutMicro);
924
+
925
+			if ($this->isRunning()) {
926
+				// Avoid exception here: process is supposed to be running, but it might have stopped just
927
+				// after this line. In any case, let's silently discard the error, we cannot do anything.
928
+				$this->doSignal($signal ?: 9, false);
929
+			}
930
+		}
931
+
932
+		if ($this->isRunning()) {
933
+			if (isset($this->fallbackStatus['pid'])) {
934
+				unset($this->fallbackStatus['pid']);
935
+
936
+				return $this->stop(0, $signal);
937
+			}
938
+			$this->close();
939
+		}
940
+
941
+		return $this->exitcode;
942
+	}
943
+
944
+	/**
945
+	 * Adds a line to the STDOUT stream.
946
+	 *
947
+	 * @internal
948
+	 */
949
+	public function addOutput(string $line)
950
+	{
951
+		$this->lastOutputTime = microtime(true);
952
+
953
+		fseek($this->stdout, 0, \SEEK_END);
954
+		fwrite($this->stdout, $line);
955
+		fseek($this->stdout, $this->incrementalOutputOffset);
956
+	}
957
+
958
+	/**
959
+	 * Adds a line to the STDERR stream.
960
+	 *
961
+	 * @internal
962
+	 */
963
+	public function addErrorOutput(string $line)
964
+	{
965
+		$this->lastOutputTime = microtime(true);
966
+
967
+		fseek($this->stderr, 0, \SEEK_END);
968
+		fwrite($this->stderr, $line);
969
+		fseek($this->stderr, $this->incrementalErrorOutputOffset);
970
+	}
971
+
972
+	/**
973
+	 * Gets the last output time in seconds.
974
+	 *
975
+	 * @return float|null The last output time in seconds or null if it isn't started
976
+	 */
977
+	public function getLastOutputTime(): ?float
978
+	{
979
+		return $this->lastOutputTime;
980
+	}
981
+
982
+	/**
983
+	 * Gets the command line to be executed.
984
+	 *
985
+	 * @return string The command to execute
986
+	 */
987
+	public function getCommandLine()
988
+	{
989
+		return \is_array($this->commandline) ? implode(' ', array_map([$this, 'escapeArgument'], $this->commandline)) : $this->commandline;
990
+	}
991
+
992
+	/**
993
+	 * Gets the process timeout (max. runtime).
994
+	 *
995
+	 * @return float|null The timeout in seconds or null if it's disabled
996
+	 */
997
+	public function getTimeout()
998
+	{
999
+		return $this->timeout;
1000
+	}
1001
+
1002
+	/**
1003
+	 * Gets the process idle timeout (max. time since last output).
1004
+	 *
1005
+	 * @return float|null The timeout in seconds or null if it's disabled
1006
+	 */
1007
+	public function getIdleTimeout()
1008
+	{
1009
+		return $this->idleTimeout;
1010
+	}
1011
+
1012
+	/**
1013
+	 * Sets the process timeout (max. runtime) in seconds.
1014
+	 *
1015
+	 * To disable the timeout, set this value to null.
1016
+	 *
1017
+	 * @return $this
1018
+	 *
1019
+	 * @throws InvalidArgumentException if the timeout is negative
1020
+	 */
1021
+	public function setTimeout(?float $timeout)
1022
+	{
1023
+		$this->timeout = $this->validateTimeout($timeout);
1024
+
1025
+		return $this;
1026
+	}
1027
+
1028
+	/**
1029
+	 * Sets the process idle timeout (max. time since last output) in seconds.
1030
+	 *
1031
+	 * To disable the timeout, set this value to null.
1032
+	 *
1033
+	 * @return $this
1034
+	 *
1035
+	 * @throws LogicException           if the output is disabled
1036
+	 * @throws InvalidArgumentException if the timeout is negative
1037
+	 */
1038
+	public function setIdleTimeout(?float $timeout)
1039
+	{
1040
+		if (null !== $timeout && $this->outputDisabled) {
1041
+			throw new LogicException('Idle timeout can not be set while the output is disabled.');
1042
+		}
1043
+
1044
+		$this->idleTimeout = $this->validateTimeout($timeout);
1045
+
1046
+		return $this;
1047
+	}
1048
+
1049
+	/**
1050
+	 * Enables or disables the TTY mode.
1051
+	 *
1052
+	 * @return $this
1053
+	 *
1054
+	 * @throws RuntimeException In case the TTY mode is not supported
1055
+	 */
1056
+	public function setTty(bool $tty)
1057
+	{
1058
+		if ('\\' === \DIRECTORY_SEPARATOR && $tty) {
1059
+			throw new RuntimeException('TTY mode is not supported on Windows platform.');
1060
+		}
1061
+
1062
+		if ($tty && !self::isTtySupported()) {
1063
+			throw new RuntimeException('TTY mode requires /dev/tty to be read/writable.');
1064
+		}
1065
+
1066
+		$this->tty = $tty;
1067
+
1068
+		return $this;
1069
+	}
1070
+
1071
+	/**
1072
+	 * Checks if the TTY mode is enabled.
1073
+	 *
1074
+	 * @return bool true if the TTY mode is enabled, false otherwise
1075
+	 */
1076
+	public function isTty()
1077
+	{
1078
+		return $this->tty;
1079
+	}
1080
+
1081
+	/**
1082
+	 * Sets PTY mode.
1083
+	 *
1084
+	 * @return $this
1085
+	 */
1086
+	public function setPty(bool $bool)
1087
+	{
1088
+		$this->pty = $bool;
1089
+
1090
+		return $this;
1091
+	}
1092
+
1093
+	/**
1094
+	 * Returns PTY state.
1095
+	 *
1096
+	 * @return bool
1097
+	 */
1098
+	public function isPty()
1099
+	{
1100
+		return $this->pty;
1101
+	}
1102
+
1103
+	/**
1104
+	 * Gets the working directory.
1105
+	 *
1106
+	 * @return string|null The current working directory or null on failure
1107
+	 */
1108
+	public function getWorkingDirectory()
1109
+	{
1110
+		if (null === $this->cwd) {
1111
+			// getcwd() will return false if any one of the parent directories does not have
1112
+			// the readable or search mode set, even if the current directory does
1113
+			return getcwd() ?: null;
1114
+		}
1115
+
1116
+		return $this->cwd;
1117
+	}
1118
+
1119
+	/**
1120
+	 * Sets the current working directory.
1121
+	 *
1122
+	 * @return $this
1123
+	 */
1124
+	public function setWorkingDirectory(string $cwd)
1125
+	{
1126
+		$this->cwd = $cwd;
1127
+
1128
+		return $this;
1129
+	}
1130
+
1131
+	/**
1132
+	 * Gets the environment variables.
1133
+	 *
1134
+	 * @return array The current environment variables
1135
+	 */
1136
+	public function getEnv()
1137
+	{
1138
+		return $this->env;
1139
+	}
1140
+
1141
+	/**
1142
+	 * Sets the environment variables.
1143
+	 *
1144
+	 * Each environment variable value should be a string.
1145
+	 * If it is an array, the variable is ignored.
1146
+	 * If it is false or null, it will be removed when
1147
+	 * env vars are otherwise inherited.
1148
+	 *
1149
+	 * That happens in PHP when 'argv' is registered into
1150
+	 * the $_ENV array for instance.
1151
+	 *
1152
+	 * @param array $env The new environment variables
1153
+	 *
1154
+	 * @return $this
1155
+	 */
1156
+	public function setEnv(array $env)
1157
+	{
1158
+		// Process can not handle env values that are arrays
1159
+		$env = array_filter($env, function ($value) {
1160
+			return !\is_array($value);
1161
+		});
1162
+
1163
+		$this->env = $env;
1164
+
1165
+		return $this;
1166
+	}
1167
+
1168
+	/**
1169
+	 * Gets the Process input.
1170
+	 *
1171
+	 * @return resource|string|\Iterator|null The Process input
1172
+	 */
1173
+	public function getInput()
1174
+	{
1175
+		return $this->input;
1176
+	}
1177
+
1178
+	/**
1179
+	 * Sets the input.
1180
+	 *
1181
+	 * This content will be passed to the underlying process standard input.
1182
+	 *
1183
+	 * @param string|int|float|bool|resource|\Traversable|null $input The content
1184
+	 *
1185
+	 * @return $this
1186
+	 *
1187
+	 * @throws LogicException In case the process is running
1188
+	 */
1189
+	public function setInput($input)
1190
+	{
1191
+		if ($this->isRunning()) {
1192
+			throw new LogicException('Input can not be set while the process is running.');
1193
+		}
1194
+
1195
+		$this->input = ProcessUtils::validateInput(__METHOD__, $input);
1196
+
1197
+		return $this;
1198
+	}
1199
+
1200
+	/**
1201
+	 * Performs a check between the timeout definition and the time the process started.
1202
+	 *
1203
+	 * In case you run a background process (with the start method), you should
1204
+	 * trigger this method regularly to ensure the process timeout
1205
+	 *
1206
+	 * @throws ProcessTimedOutException In case the timeout was reached
1207
+	 */
1208
+	public function checkTimeout()
1209
+	{
1210
+		if (self::STATUS_STARTED !== $this->status) {
1211
+			return;
1212
+		}
1213
+
1214
+		if (null !== $this->timeout && $this->timeout < microtime(true) - $this->starttime) {
1215
+			$this->stop(0);
1216
+
1217
+			throw new ProcessTimedOutException($this, ProcessTimedOutException::TYPE_GENERAL);
1218
+		}
1219
+
1220
+		if (null !== $this->idleTimeout && $this->idleTimeout < microtime(true) - $this->lastOutputTime) {
1221
+			$this->stop(0);
1222
+
1223
+			throw new ProcessTimedOutException($this, ProcessTimedOutException::TYPE_IDLE);
1224
+		}
1225
+	}
1226
+
1227
+	/**
1228
+	 * @throws LogicException in case process is not started
1229
+	 */
1230
+	public function getStartTime(): float
1231
+	{
1232
+		if (!$this->isStarted()) {
1233
+			throw new LogicException('Start time is only available after process start.');
1234
+		}
1235
+
1236
+		return $this->starttime;
1237
+	}
1238
+
1239
+	/**
1240
+	 * Defines options to pass to the underlying proc_open().
1241
+	 *
1242
+	 * @see https://php.net/proc_open for the options supported by PHP.
1243
+	 *
1244
+	 * Enabling the "create_new_console" option allows a subprocess to continue
1245
+	 * to run after the main process exited, on both Windows and *nix
1246
+	 */
1247
+	public function setOptions(array $options)
1248
+	{
1249
+		if ($this->isRunning()) {
1250
+			throw new RuntimeException('Setting options while the process is running is not possible.');
1251
+		}
1252
+
1253
+		$defaultOptions = $this->options;
1254
+		$existingOptions = ['blocking_pipes', 'create_process_group', 'create_new_console'];
1255
+
1256
+		foreach ($options as $key => $value) {
1257
+			if (!\in_array($key, $existingOptions)) {
1258
+				$this->options = $defaultOptions;
1259
+				throw new LogicException(sprintf('Invalid option "%s" passed to "%s()". Supported options are "%s".', $key, __METHOD__, implode('", "', $existingOptions)));
1260
+			}
1261
+			$this->options[$key] = $value;
1262
+		}
1263
+	}
1264
+
1265
+	/**
1266
+	 * Returns whether TTY is supported on the current operating system.
1267
+	 */
1268
+	public static function isTtySupported(): bool
1269
+	{
1270
+		static $isTtySupported;
1271
+
1272
+		if (null === $isTtySupported) {
1273
+			$isTtySupported = (bool) @proc_open('echo 1 >/dev/null', [['file', '/dev/tty', 'r'], ['file', '/dev/tty', 'w'], ['file', '/dev/tty', 'w']], $pipes);
1274
+		}
1275
+
1276
+		return $isTtySupported;
1277
+	}
1278
+
1279
+	/**
1280
+	 * Returns whether PTY is supported on the current operating system.
1281
+	 *
1282
+	 * @return bool
1283
+	 */
1284
+	public static function isPtySupported()
1285
+	{
1286
+		static $result;
1287
+
1288
+		if (null !== $result) {
1289
+			return $result;
1290
+		}
1291
+
1292
+		if ('\\' === \DIRECTORY_SEPARATOR) {
1293
+			return $result = false;
1294
+		}
1295
+
1296
+		return $result = (bool) @proc_open('echo 1 >/dev/null', [['pty'], ['pty'], ['pty']], $pipes);
1297
+	}
1298
+
1299
+	/**
1300
+	 * Creates the descriptors needed by the proc_open.
1301
+	 */
1302
+	private function getDescriptors(): array
1303
+	{
1304
+		if ($this->input instanceof \Iterator) {
1305
+			$this->input->rewind();
1306
+		}
1307
+		if ('\\' === \DIRECTORY_SEPARATOR) {
1308
+			$this->processPipes = new WindowsPipes($this->input, !$this->outputDisabled || $this->hasCallback);
1309
+		} else {
1310
+			$this->processPipes = new UnixPipes($this->isTty(), $this->isPty(), $this->input, !$this->outputDisabled || $this->hasCallback);
1311
+		}
1312
+
1313
+		return $this->processPipes->getDescriptors();
1314
+	}
1315
+
1316
+	/**
1317
+	 * Builds up the callback used by wait().
1318
+	 *
1319
+	 * The callbacks adds all occurred output to the specific buffer and calls
1320
+	 * the user callback (if present) with the received output.
1321
+	 *
1322
+	 * @param callable|null $callback The user defined PHP callback
1323
+	 *
1324
+	 * @return \Closure A PHP closure
1325
+	 */
1326
+	protected function buildCallback(callable $callback = null)
1327
+	{
1328
+		if ($this->outputDisabled) {
1329
+			return function ($type, $data) use ($callback): bool {
1330
+				return null !== $callback && $callback($type, $data);
1331
+			};
1332
+		}
1333
+
1334
+		$out = self::OUT;
1335
+
1336
+		return function ($type, $data) use ($callback, $out): bool {
1337
+			if ($out == $type) {
1338
+				$this->addOutput($data);
1339
+			} else {
1340
+				$this->addErrorOutput($data);
1341
+			}
1342
+
1343
+			return null !== $callback && $callback($type, $data);
1344
+		};
1345
+	}
1346
+
1347
+	/**
1348
+	 * Updates the status of the process, reads pipes.
1349
+	 *
1350
+	 * @param bool $blocking Whether to use a blocking read call
1351
+	 */
1352
+	protected function updateStatus(bool $blocking)
1353
+	{
1354
+		if (self::STATUS_STARTED !== $this->status) {
1355
+			return;
1356
+		}
1357
+
1358
+		$this->processInformation = proc_get_status($this->process);
1359
+		$running = $this->processInformation['running'];
1360
+
1361
+		$this->readPipes($running && $blocking, '\\' !== \DIRECTORY_SEPARATOR || !$running);
1362
+
1363
+		if ($this->fallbackStatus && $this->isSigchildEnabled()) {
1364
+			$this->processInformation = $this->fallbackStatus + $this->processInformation;
1365
+		}
1366
+
1367
+		if (!$running) {
1368
+			$this->close();
1369
+		}
1370
+	}
1371
+
1372
+	/**
1373
+	 * Returns whether PHP has been compiled with the '--enable-sigchild' option or not.
1374
+	 *
1375
+	 * @return bool
1376
+	 */
1377
+	protected function isSigchildEnabled()
1378
+	{
1379
+		if (null !== self::$sigchild) {
1380
+			return self::$sigchild;
1381
+		}
1382
+
1383
+		if (!\function_exists('phpinfo')) {
1384
+			return self::$sigchild = false;
1385
+		}
1386
+
1387
+		ob_start();
1388
+		phpinfo(\INFO_GENERAL);
1389
+
1390
+		return self::$sigchild = str_contains(ob_get_clean(), '--enable-sigchild');
1391
+	}
1392
+
1393
+	/**
1394
+	 * Reads pipes for the freshest output.
1395
+	 *
1396
+	 * @param string $caller   The name of the method that needs fresh outputs
1397
+	 * @param bool   $blocking Whether to use blocking calls or not
1398
+	 *
1399
+	 * @throws LogicException in case output has been disabled or process is not started
1400
+	 */
1401
+	private function readPipesForOutput(string $caller, bool $blocking = false)
1402
+	{
1403
+		if ($this->outputDisabled) {
1404
+			throw new LogicException('Output has been disabled.');
1405
+		}
1406
+
1407
+		$this->requireProcessIsStarted($caller);
1408
+
1409
+		$this->updateStatus($blocking);
1410
+	}
1411
+
1412
+	/**
1413
+	 * Validates and returns the filtered timeout.
1414
+	 *
1415
+	 * @throws InvalidArgumentException if the given timeout is a negative number
1416
+	 */
1417
+	private function validateTimeout(?float $timeout): ?float
1418
+	{
1419
+		$timeout = (float) $timeout;
1420
+
1421
+		if (0.0 === $timeout) {
1422
+			$timeout = null;
1423
+		} elseif ($timeout < 0) {
1424
+			throw new InvalidArgumentException('The timeout value must be a valid positive integer or float number.');
1425
+		}
1426
+
1427
+		return $timeout;
1428
+	}
1429
+
1430
+	/**
1431
+	 * Reads pipes, executes callback.
1432
+	 *
1433
+	 * @param bool $blocking Whether to use blocking calls or not
1434
+	 * @param bool $close    Whether to close file handles or not
1435
+	 */
1436
+	private function readPipes(bool $blocking, bool $close)
1437
+	{
1438
+		$result = $this->processPipes->readAndWrite($blocking, $close);
1439
+
1440
+		$callback = $this->callback;
1441
+		foreach ($result as $type => $data) {
1442
+			if (3 !== $type) {
1443
+				$callback(self::STDOUT === $type ? self::OUT : self::ERR, $data);
1444
+			} elseif (!isset($this->fallbackStatus['signaled'])) {
1445
+				$this->fallbackStatus['exitcode'] = (int) $data;
1446
+			}
1447
+		}
1448
+	}
1449
+
1450
+	/**
1451
+	 * Closes process resource, closes file handles, sets the exitcode.
1452
+	 *
1453
+	 * @return int The exitcode
1454
+	 */
1455
+	private function close(): int
1456
+	{
1457
+		$this->processPipes->close();
1458
+		if (\is_resource($this->process)) {
1459
+			proc_close($this->process);
1460
+		}
1461
+		$this->exitcode = $this->processInformation['exitcode'];
1462
+		$this->status = self::STATUS_TERMINATED;
1463
+
1464
+		if (-1 === $this->exitcode) {
1465
+			if ($this->processInformation['signaled'] && 0 < $this->processInformation['termsig']) {
1466
+				// if process has been signaled, no exitcode but a valid termsig, apply Unix convention
1467
+				$this->exitcode = 128 + $this->processInformation['termsig'];
1468
+			} elseif ($this->isSigchildEnabled()) {
1469
+				$this->processInformation['signaled'] = true;
1470
+				$this->processInformation['termsig'] = -1;
1471
+			}
1472
+		}
1473
+
1474
+		// Free memory from self-reference callback created by buildCallback
1475
+		// Doing so in other contexts like __destruct or by garbage collector is ineffective
1476
+		// Now pipes are closed, so the callback is no longer necessary
1477
+		$this->callback = null;
1478
+
1479
+		return $this->exitcode;
1480
+	}
1481
+
1482
+	/**
1483
+	 * Resets data related to the latest run of the process.
1484
+	 */
1485
+	private function resetProcessData()
1486
+	{
1487
+		$this->starttime = null;
1488
+		$this->callback = null;
1489
+		$this->exitcode = null;
1490
+		$this->fallbackStatus = [];
1491
+		$this->processInformation = null;
1492
+		$this->stdout = fopen('php://temp/maxmemory:'.(1024 * 1024), 'w+');
1493
+		$this->stderr = fopen('php://temp/maxmemory:'.(1024 * 1024), 'w+');
1494
+		$this->process = null;
1495
+		$this->latestSignal = null;
1496
+		$this->status = self::STATUS_READY;
1497
+		$this->incrementalOutputOffset = 0;
1498
+		$this->incrementalErrorOutputOffset = 0;
1499
+	}
1500
+
1501
+	/**
1502
+	 * Sends a POSIX signal to the process.
1503
+	 *
1504
+	 * @param int  $signal         A valid POSIX signal (see https://php.net/pcntl.constants)
1505
+	 * @param bool $throwException Whether to throw exception in case signal failed
1506
+	 *
1507
+	 * @return bool True if the signal was sent successfully, false otherwise
1508
+	 *
1509
+	 * @throws LogicException   In case the process is not running
1510
+	 * @throws RuntimeException In case --enable-sigchild is activated and the process can't be killed
1511
+	 * @throws RuntimeException In case of failure
1512
+	 */
1513
+	private function doSignal(int $signal, bool $throwException): bool
1514
+	{
1515
+		if (null === $pid = $this->getPid()) {
1516
+			if ($throwException) {
1517
+				throw new LogicException('Can not send signal on a non running process.');
1518
+			}
1519
+
1520
+			return false;
1521
+		}
1522
+
1523
+		if ('\\' === \DIRECTORY_SEPARATOR) {
1524
+			exec(sprintf('taskkill /F /T /PID %d 2>&1', $pid), $output, $exitCode);
1525
+			if ($exitCode && $this->isRunning()) {
1526
+				if ($throwException) {
1527
+					throw new RuntimeException(sprintf('Unable to kill the process (%s).', implode(' ', $output)));
1528
+				}
1529
+
1530
+				return false;
1531
+			}
1532
+		} else {
1533
+			if (!$this->isSigchildEnabled()) {
1534
+				$ok = @proc_terminate($this->process, $signal);
1535
+			} elseif (\function_exists('posix_kill')) {
1536
+				$ok = @posix_kill($pid, $signal);
1537
+			} elseif ($ok = proc_open(sprintf('kill -%d %d', $signal, $pid), [2 => ['pipe', 'w']], $pipes)) {
1538
+				$ok = false === fgets($pipes[2]);
1539
+			}
1540
+			if (!$ok) {
1541
+				if ($throwException) {
1542
+					throw new RuntimeException(sprintf('Error while sending signal "%s".', $signal));
1543
+				}
1544
+
1545
+				return false;
1546
+			}
1547
+		}
1548
+
1549
+		$this->latestSignal = $signal;
1550
+		$this->fallbackStatus['signaled'] = true;
1551
+		$this->fallbackStatus['exitcode'] = -1;
1552
+		$this->fallbackStatus['termsig'] = $this->latestSignal;
1553
+
1554
+		return true;
1555
+	}
1556
+
1557
+	private function prepareWindowsCommandLine(string $cmd, array &$env): string
1558
+	{
1559
+		$uid = uniqid('', true);
1560
+		$varCount = 0;
1561
+		$varCache = [];
1562
+		$cmd = preg_replace_callback(
1563
+			'/"(?:(
1564 1564
                 [^"%!^]*+
1565 1565
                 (?:
1566 1566
                     (?: !LF! | "(?:\^[%!^])?+" )
1567 1567
                     [^"%!^]*+
1568 1568
                 )++
1569 1569
             ) | [^"]*+ )"/x',
1570
-            function ($m) use (&$env, &$varCache, &$varCount, $uid) {
1571
-                if (!isset($m[1])) {
1572
-                    return $m[0];
1573
-                }
1574
-                if (isset($varCache[$m[0]])) {
1575
-                    return $varCache[$m[0]];
1576
-                }
1577
-                if (str_contains($value = $m[1], "\0")) {
1578
-                    $value = str_replace("\0", '?', $value);
1579
-                }
1580
-                if (false === strpbrk($value, "\"%!\n")) {
1581
-                    return '"'.$value.'"';
1582
-                }
1583
-
1584
-                $value = str_replace(['!LF!', '"^!"', '"^%"', '"^^"', '""'], ["\n", '!', '%', '^', '"'], $value);
1585
-                $value = '"'.preg_replace('/(\\\\*)"/', '$1$1\\"', $value).'"';
1586
-                $var = $uid.++$varCount;
1587
-
1588
-                $env[$var] = $value;
1589
-
1590
-                return $varCache[$m[0]] = '!'.$var.'!';
1591
-            },
1592
-            $cmd
1593
-        );
1594
-
1595
-        $cmd = 'cmd /V:ON /E:ON /D /C ('.str_replace("\n", ' ', $cmd).')';
1596
-        foreach ($this->processPipes->getFiles() as $offset => $filename) {
1597
-            $cmd .= ' '.$offset.'>"'.$filename.'"';
1598
-        }
1599
-
1600
-        return $cmd;
1601
-    }
1602
-
1603
-    /**
1604
-     * Ensures the process is running or terminated, throws a LogicException if the process has a not started.
1605
-     *
1606
-     * @throws LogicException if the process has not run
1607
-     */
1608
-    private function requireProcessIsStarted(string $functionName)
1609
-    {
1610
-        if (!$this->isStarted()) {
1611
-            throw new LogicException(sprintf('Process must be started before calling "%s()".', $functionName));
1612
-        }
1613
-    }
1614
-
1615
-    /**
1616
-     * Ensures the process is terminated, throws a LogicException if the process has a status different than "terminated".
1617
-     *
1618
-     * @throws LogicException if the process is not yet terminated
1619
-     */
1620
-    private function requireProcessIsTerminated(string $functionName)
1621
-    {
1622
-        if (!$this->isTerminated()) {
1623
-            throw new LogicException(sprintf('Process must be terminated before calling "%s()".', $functionName));
1624
-        }
1625
-    }
1626
-
1627
-    /**
1628
-     * Escapes a string to be used as a shell argument.
1629
-     */
1630
-    private function escapeArgument(?string $argument): string
1631
-    {
1632
-        if ('' === $argument || null === $argument) {
1633
-            return '""';
1634
-        }
1635
-        if ('\\' !== \DIRECTORY_SEPARATOR) {
1636
-            return "'".str_replace("'", "'\\''", $argument)."'";
1637
-        }
1638
-        if (str_contains($argument, "\0")) {
1639
-            $argument = str_replace("\0", '?', $argument);
1640
-        }
1641
-        if (!preg_match('/[\/()%!^"<>&|\s]/', $argument)) {
1642
-            return $argument;
1643
-        }
1644
-        $argument = preg_replace('/(\\\\+)$/', '$1$1', $argument);
1645
-
1646
-        return '"'.str_replace(['"', '^', '%', '!', "\n"], ['""', '"^^"', '"^%"', '"^!"', '!LF!'], $argument).'"';
1647
-    }
1648
-
1649
-    private function replacePlaceholders(string $commandline, array $env)
1650
-    {
1651
-        return preg_replace_callback('/"\$\{:([_a-zA-Z]++[_a-zA-Z0-9]*+)\}"/', function ($matches) use ($commandline, $env) {
1652
-            if (!isset($env[$matches[1]]) || false === $env[$matches[1]]) {
1653
-                throw new InvalidArgumentException(sprintf('Command line is missing a value for parameter "%s": ', $matches[1]).$commandline);
1654
-            }
1655
-
1656
-            return $this->escapeArgument($env[$matches[1]]);
1657
-        }, $commandline);
1658
-    }
1659
-
1660
-    private function getDefaultEnv(): array
1661
-    {
1662
-        $env = [];
1663
-
1664
-        foreach ($_SERVER as $k => $v) {
1665
-            if (\is_string($v) && false !== $v = getenv($k)) {
1666
-                $env[$k] = $v;
1667
-            }
1668
-        }
1669
-
1670
-        foreach ($_ENV as $k => $v) {
1671
-            if (\is_string($v)) {
1672
-                $env[$k] = $v;
1673
-            }
1674
-        }
1675
-
1676
-        return $env;
1677
-    }
1570
+			function ($m) use (&$env, &$varCache, &$varCount, $uid) {
1571
+				if (!isset($m[1])) {
1572
+					return $m[0];
1573
+				}
1574
+				if (isset($varCache[$m[0]])) {
1575
+					return $varCache[$m[0]];
1576
+				}
1577
+				if (str_contains($value = $m[1], "\0")) {
1578
+					$value = str_replace("\0", '?', $value);
1579
+				}
1580
+				if (false === strpbrk($value, "\"%!\n")) {
1581
+					return '"'.$value.'"';
1582
+				}
1583
+
1584
+				$value = str_replace(['!LF!', '"^!"', '"^%"', '"^^"', '""'], ["\n", '!', '%', '^', '"'], $value);
1585
+				$value = '"'.preg_replace('/(\\\\*)"/', '$1$1\\"', $value).'"';
1586
+				$var = $uid.++$varCount;
1587
+
1588
+				$env[$var] = $value;
1589
+
1590
+				return $varCache[$m[0]] = '!'.$var.'!';
1591
+			},
1592
+			$cmd
1593
+		);
1594
+
1595
+		$cmd = 'cmd /V:ON /E:ON /D /C ('.str_replace("\n", ' ', $cmd).')';
1596
+		foreach ($this->processPipes->getFiles() as $offset => $filename) {
1597
+			$cmd .= ' '.$offset.'>"'.$filename.'"';
1598
+		}
1599
+
1600
+		return $cmd;
1601
+	}
1602
+
1603
+	/**
1604
+	 * Ensures the process is running or terminated, throws a LogicException if the process has a not started.
1605
+	 *
1606
+	 * @throws LogicException if the process has not run
1607
+	 */
1608
+	private function requireProcessIsStarted(string $functionName)
1609
+	{
1610
+		if (!$this->isStarted()) {
1611
+			throw new LogicException(sprintf('Process must be started before calling "%s()".', $functionName));
1612
+		}
1613
+	}
1614
+
1615
+	/**
1616
+	 * Ensures the process is terminated, throws a LogicException if the process has a status different than "terminated".
1617
+	 *
1618
+	 * @throws LogicException if the process is not yet terminated
1619
+	 */
1620
+	private function requireProcessIsTerminated(string $functionName)
1621
+	{
1622
+		if (!$this->isTerminated()) {
1623
+			throw new LogicException(sprintf('Process must be terminated before calling "%s()".', $functionName));
1624
+		}
1625
+	}
1626
+
1627
+	/**
1628
+	 * Escapes a string to be used as a shell argument.
1629
+	 */
1630
+	private function escapeArgument(?string $argument): string
1631
+	{
1632
+		if ('' === $argument || null === $argument) {
1633
+			return '""';
1634
+		}
1635
+		if ('\\' !== \DIRECTORY_SEPARATOR) {
1636
+			return "'".str_replace("'", "'\\''", $argument)."'";
1637
+		}
1638
+		if (str_contains($argument, "\0")) {
1639
+			$argument = str_replace("\0", '?', $argument);
1640
+		}
1641
+		if (!preg_match('/[\/()%!^"<>&|\s]/', $argument)) {
1642
+			return $argument;
1643
+		}
1644
+		$argument = preg_replace('/(\\\\+)$/', '$1$1', $argument);
1645
+
1646
+		return '"'.str_replace(['"', '^', '%', '!', "\n"], ['""', '"^^"', '"^%"', '"^!"', '!LF!'], $argument).'"';
1647
+	}
1648
+
1649
+	private function replacePlaceholders(string $commandline, array $env)
1650
+	{
1651
+		return preg_replace_callback('/"\$\{:([_a-zA-Z]++[_a-zA-Z0-9]*+)\}"/', function ($matches) use ($commandline, $env) {
1652
+			if (!isset($env[$matches[1]]) || false === $env[$matches[1]]) {
1653
+				throw new InvalidArgumentException(sprintf('Command line is missing a value for parameter "%s": ', $matches[1]).$commandline);
1654
+			}
1655
+
1656
+			return $this->escapeArgument($env[$matches[1]]);
1657
+		}, $commandline);
1658
+	}
1659
+
1660
+	private function getDefaultEnv(): array
1661
+	{
1662
+		$env = [];
1663
+
1664
+		foreach ($_SERVER as $k => $v) {
1665
+			if (\is_string($v) && false !== $v = getenv($k)) {
1666
+				$env[$k] = $v;
1667
+			}
1668
+		}
1669
+
1670
+		foreach ($_ENV as $k => $v) {
1671
+			if (\is_string($v)) {
1672
+				$env[$k] = $v;
1673
+			}
1674
+		}
1675
+
1676
+		return $env;
1677
+	}
1678 1678
 }
Please login to merge, or discard this patch.
Spacing   +338 added lines, -338 removed lines patch added patch discarded remove patch
@@ -45,9 +45,9 @@  discard block
 block discarded – undo
45 45
     public const TIMEOUT_PRECISION = 0.2;
46 46
 
47 47
     public const ITER_NON_BLOCKING = 1; // By default, iterating over outputs is a blocking call, use this flag to make it non-blocking
48
-    public const ITER_KEEP_OUTPUT = 2;  // By default, outputs are cleared while iterating, use this flag to keep them in memory
49
-    public const ITER_SKIP_OUT = 4;     // Use this flag to skip STDOUT while iterating
50
-    public const ITER_SKIP_ERR = 8;     // Use this flag to skip STDERR while iterating
48
+    public const ITER_KEEP_OUTPUT = 2; // By default, outputs are cleared while iterating, use this flag to keep them in memory
49
+    public const ITER_SKIP_OUT = 4; // Use this flag to skip STDOUT while iterating
50
+    public const ITER_SKIP_ERR = 8; // Use this flag to skip STDERR while iterating
51 51
 
52 52
     private $callback;
53 53
     private $hasCallback = false;
@@ -60,7 +60,7 @@  discard block
 block discarded – undo
60 60
     private $timeout;
61 61
     private $idleTimeout;
62 62
     private $exitcode;
63
-    private $fallbackStatus = [];
63
+    private $fallbackStatus = [ ];
64 64
     private $processInformation;
65 65
     private $outputDisabled = false;
66 66
     private $stdout;
@@ -71,7 +71,7 @@  discard block
 block discarded – undo
71 71
     private $incrementalErrorOutputOffset = 0;
72 72
     private $tty = false;
73 73
     private $pty;
74
-    private $options = ['suppress_errors' => true, 'bypass_shell' => true];
74
+    private $options = [ 'suppress_errors' => true, 'bypass_shell' => true ];
75 75
 
76 76
     private $useFileHandles = false;
77 77
     /** @var PipesInterface */
@@ -138,10 +138,10 @@  discard block
 block discarded – undo
138 138
      *
139 139
      * @throws LogicException When proc_open is not installed
140 140
      */
141
-    public function __construct(array $command, string $cwd = null, array $env = null, $input = null, ?float $timeout = 60)
141
+    public function __construct( array $command, string $cwd = null, array $env = null, $input = null, ?float $timeout = 60 )
142 142
     {
143
-        if (!\function_exists('proc_open')) {
144
-            throw new LogicException('The Process class relies on proc_open, which is not available on your PHP installation.');
143
+        if ( ! \function_exists( 'proc_open' ) ) {
144
+            throw new LogicException( 'The Process class relies on proc_open, which is not available on your PHP installation.' );
145 145
         }
146 146
 
147 147
         $this->commandline = $command;
@@ -151,15 +151,15 @@  discard block
 block discarded – undo
151 151
         // on Gnu/Linux, PHP builds with --enable-maintainer-zts are also affected
152 152
         // @see : https://bugs.php.net/51800
153 153
         // @see : https://bugs.php.net/50524
154
-        if (null === $this->cwd && (\defined('ZEND_THREAD_SAFE') || '\\' === \DIRECTORY_SEPARATOR)) {
154
+        if ( null === $this->cwd && ( \defined( 'ZEND_THREAD_SAFE' ) || '\\' === \DIRECTORY_SEPARATOR ) ) {
155 155
             $this->cwd = getcwd();
156 156
         }
157
-        if (null !== $env) {
158
-            $this->setEnv($env);
157
+        if ( null !== $env ) {
158
+            $this->setEnv( $env );
159 159
         }
160 160
 
161
-        $this->setInput($input);
162
-        $this->setTimeout($timeout);
161
+        $this->setInput( $input );
162
+        $this->setTimeout( $timeout );
163 163
         $this->useFileHandles = '\\' === \DIRECTORY_SEPARATOR;
164 164
         $this->pty = false;
165 165
     }
@@ -187,9 +187,9 @@  discard block
 block discarded – undo
187 187
      *
188 188
      * @throws LogicException When proc_open is not installed
189 189
      */
190
-    public static function fromShellCommandline(string $command, string $cwd = null, array $env = null, $input = null, ?float $timeout = 60)
190
+    public static function fromShellCommandline( string $command, string $cwd = null, array $env = null, $input = null, ?float $timeout = 60 )
191 191
     {
192
-        $process = new static([], $cwd, $env, $input, $timeout);
192
+        $process = new static( [ ], $cwd, $env, $input, $timeout );
193 193
         $process->commandline = $command;
194 194
 
195 195
         return $process;
@@ -200,20 +200,20 @@  discard block
 block discarded – undo
200 200
      */
201 201
     public function __sleep()
202 202
     {
203
-        throw new \BadMethodCallException('Cannot serialize '.__CLASS__);
203
+        throw new \BadMethodCallException( 'Cannot serialize ' . __CLASS__ );
204 204
     }
205 205
 
206 206
     public function __wakeup()
207 207
     {
208
-        throw new \BadMethodCallException('Cannot unserialize '.__CLASS__);
208
+        throw new \BadMethodCallException( 'Cannot unserialize ' . __CLASS__ );
209 209
     }
210 210
 
211 211
     public function __destruct()
212 212
     {
213
-        if ($this->options['create_new_console'] ?? false) {
213
+        if ( $this->options[ 'create_new_console' ] ?? false ) {
214 214
             $this->processPipes->close();
215 215
         } else {
216
-            $this->stop(0);
216
+            $this->stop( 0 );
217 217
         }
218 218
     }
219 219
 
@@ -245,9 +245,9 @@  discard block
 block discarded – undo
245 245
      *
246 246
      * @final
247 247
      */
248
-    public function run(callable $callback = null, array $env = []): int
248
+    public function run( callable $callback = null, array $env = [ ] ): int
249 249
     {
250
-        $this->start($callback, $env);
250
+        $this->start( $callback, $env );
251 251
 
252 252
         return $this->wait();
253 253
     }
@@ -264,10 +264,10 @@  discard block
 block discarded – undo
264 264
      *
265 265
      * @final
266 266
      */
267
-    public function mustRun(callable $callback = null, array $env = []): self
267
+    public function mustRun( callable $callback = null, array $env = [ ] ): self
268 268
     {
269
-        if (0 !== $this->run($callback, $env)) {
270
-            throw new ProcessFailedException($this);
269
+        if ( 0 !== $this->run( $callback, $env ) ) {
270
+            throw new ProcessFailedException( $this );
271 271
         }
272 272
 
273 273
         return $this;
@@ -292,77 +292,77 @@  discard block
 block discarded – undo
292 292
      * @throws RuntimeException When process is already running
293 293
      * @throws LogicException   In case a callback is provided and output has been disabled
294 294
      */
295
-    public function start(callable $callback = null, array $env = [])
295
+    public function start( callable $callback = null, array $env = [ ] )
296 296
     {
297
-        if ($this->isRunning()) {
298
-            throw new RuntimeException('Process is already running.');
297
+        if ( $this->isRunning() ) {
298
+            throw new RuntimeException( 'Process is already running.' );
299 299
         }
300 300
 
301 301
         $this->resetProcessData();
302
-        $this->starttime = $this->lastOutputTime = microtime(true);
303
-        $this->callback = $this->buildCallback($callback);
302
+        $this->starttime = $this->lastOutputTime = microtime( true );
303
+        $this->callback = $this->buildCallback( $callback );
304 304
         $this->hasCallback = null !== $callback;
305 305
         $descriptors = $this->getDescriptors();
306 306
 
307
-        if ($this->env) {
307
+        if ( $this->env ) {
308 308
             $env += $this->env;
309 309
         }
310 310
 
311 311
         $env += $this->getDefaultEnv();
312 312
 
313
-        if (\is_array($commandline = $this->commandline)) {
314
-            $commandline = implode(' ', array_map([$this, 'escapeArgument'], $commandline));
313
+        if ( \is_array( $commandline = $this->commandline ) ) {
314
+            $commandline = implode( ' ', array_map( [ $this, 'escapeArgument' ], $commandline ) );
315 315
 
316
-            if ('\\' !== \DIRECTORY_SEPARATOR) {
316
+            if ( '\\' !== \DIRECTORY_SEPARATOR ) {
317 317
                 // exec is mandatory to deal with sending a signal to the process
318
-                $commandline = 'exec '.$commandline;
318
+                $commandline = 'exec ' . $commandline;
319 319
             }
320 320
         } else {
321
-            $commandline = $this->replacePlaceholders($commandline, $env);
321
+            $commandline = $this->replacePlaceholders( $commandline, $env );
322 322
         }
323 323
 
324
-        if ('\\' === \DIRECTORY_SEPARATOR) {
325
-            $commandline = $this->prepareWindowsCommandLine($commandline, $env);
326
-        } elseif (!$this->useFileHandles && $this->isSigchildEnabled()) {
324
+        if ( '\\' === \DIRECTORY_SEPARATOR ) {
325
+            $commandline = $this->prepareWindowsCommandLine( $commandline, $env );
326
+        } elseif ( ! $this->useFileHandles && $this->isSigchildEnabled() ) {
327 327
             // last exit code is output on the fourth pipe and caught to work around --enable-sigchild
328
-            $descriptors[3] = ['pipe', 'w'];
328
+            $descriptors[ 3 ] = [ 'pipe', 'w' ];
329 329
 
330 330
             // See https://unix.stackexchange.com/questions/71205/background-process-pipe-input
331
-            $commandline = '{ ('.$commandline.') <&3 3<&- 3>/dev/null & } 3<&0;';
331
+            $commandline = '{ (' . $commandline . ') <&3 3<&- 3>/dev/null & } 3<&0;';
332 332
             $commandline .= 'pid=$!; echo $pid >&3; wait $pid; code=$?; echo $code >&3; exit $code';
333 333
 
334 334
             // Workaround for the bug, when PTS functionality is enabled.
335 335
             // @see : https://bugs.php.net/69442
336
-            $ptsWorkaround = fopen(__FILE__, 'r');
336
+            $ptsWorkaround = fopen( __FILE__, 'r' );
337 337
         }
338 338
 
339
-        $envPairs = [];
340
-        foreach ($env as $k => $v) {
341
-            if (false !== $v) {
342
-                $envPairs[] = $k.'='.$v;
339
+        $envPairs = [ ];
340
+        foreach ( $env as $k => $v ) {
341
+            if ( false !== $v ) {
342
+                $envPairs[ ] = $k . '=' . $v;
343 343
             }
344 344
         }
345 345
 
346
-        if (!is_dir($this->cwd)) {
347
-            throw new RuntimeException(sprintf('The provided cwd "%s" does not exist.', $this->cwd));
346
+        if ( ! is_dir( $this->cwd ) ) {
347
+            throw new RuntimeException( sprintf( 'The provided cwd "%s" does not exist.', $this->cwd ) );
348 348
         }
349 349
 
350
-        $this->process = @proc_open($commandline, $descriptors, $this->processPipes->pipes, $this->cwd, $envPairs, $this->options);
350
+        $this->process = @proc_open( $commandline, $descriptors, $this->processPipes->pipes, $this->cwd, $envPairs, $this->options );
351 351
 
352
-        if (!\is_resource($this->process)) {
353
-            throw new RuntimeException('Unable to launch a new process.');
352
+        if ( ! \is_resource( $this->process ) ) {
353
+            throw new RuntimeException( 'Unable to launch a new process.' );
354 354
         }
355 355
         $this->status = self::STATUS_STARTED;
356 356
 
357
-        if (isset($descriptors[3])) {
358
-            $this->fallbackStatus['pid'] = (int) fgets($this->processPipes->pipes[3]);
357
+        if ( isset( $descriptors[ 3 ] ) ) {
358
+            $this->fallbackStatus[ 'pid' ] = (int)fgets( $this->processPipes->pipes[ 3 ] );
359 359
         }
360 360
 
361
-        if ($this->tty) {
361
+        if ( $this->tty ) {
362 362
             return;
363 363
         }
364 364
 
365
-        $this->updateStatus(false);
365
+        $this->updateStatus( false );
366 366
         $this->checkTimeout();
367 367
     }
368 368
 
@@ -383,14 +383,14 @@  discard block
 block discarded – undo
383 383
      *
384 384
      * @final
385 385
      */
386
-    public function restart(callable $callback = null, array $env = []): self
386
+    public function restart( callable $callback = null, array $env = [ ] ): self
387 387
     {
388
-        if ($this->isRunning()) {
389
-            throw new RuntimeException('Process is already running.');
388
+        if ( $this->isRunning() ) {
389
+            throw new RuntimeException( 'Process is already running.' );
390 390
         }
391 391
 
392 392
         $process = clone $this;
393
-        $process->start($callback, $env);
393
+        $process->start( $callback, $env );
394 394
 
395 395
         return $process;
396 396
     }
@@ -410,33 +410,33 @@  discard block
 block discarded – undo
410 410
      * @throws ProcessSignaledException When process stopped after receiving signal
411 411
      * @throws LogicException           When process is not yet started
412 412
      */
413
-    public function wait(callable $callback = null)
413
+    public function wait( callable $callback = null )
414 414
     {
415
-        $this->requireProcessIsStarted(__FUNCTION__);
415
+        $this->requireProcessIsStarted( __FUNCTION__ );
416 416
 
417
-        $this->updateStatus(false);
417
+        $this->updateStatus( false );
418 418
 
419
-        if (null !== $callback) {
420
-            if (!$this->processPipes->haveReadSupport()) {
421
-                $this->stop(0);
422
-                throw new LogicException('Pass the callback to the "Process::start" method or call enableOutput to use a callback with "Process::wait".');
419
+        if ( null !== $callback ) {
420
+            if ( ! $this->processPipes->haveReadSupport() ) {
421
+                $this->stop( 0 );
422
+                throw new LogicException( 'Pass the callback to the "Process::start" method or call enableOutput to use a callback with "Process::wait".' );
423 423
             }
424
-            $this->callback = $this->buildCallback($callback);
424
+            $this->callback = $this->buildCallback( $callback );
425 425
         }
426 426
 
427 427
         do {
428 428
             $this->checkTimeout();
429 429
             $running = '\\' === \DIRECTORY_SEPARATOR ? $this->isRunning() : $this->processPipes->areOpen();
430
-            $this->readPipes($running, '\\' !== \DIRECTORY_SEPARATOR || !$running);
431
-        } while ($running);
430
+            $this->readPipes( $running, '\\' !== \DIRECTORY_SEPARATOR || ! $running );
431
+        } while ( $running );
432 432
 
433
-        while ($this->isRunning()) {
433
+        while ( $this->isRunning() ) {
434 434
             $this->checkTimeout();
435
-            usleep(1000);
435
+            usleep( 1000 );
436 436
         }
437 437
 
438
-        if ($this->processInformation['signaled'] && $this->processInformation['termsig'] !== $this->latestSignal) {
439
-            throw new ProcessSignaledException($this);
438
+        if ( $this->processInformation[ 'signaled' ] && $this->processInformation[ 'termsig' ] !== $this->latestSignal ) {
439
+            throw new ProcessSignaledException( $this );
440 440
         }
441 441
 
442 442
         return $this->exitcode;
@@ -453,38 +453,38 @@  discard block
 block discarded – undo
453 453
      * @throws LogicException           When process is not yet started
454 454
      * @throws ProcessTimedOutException In case the timeout was reached
455 455
      */
456
-    public function waitUntil(callable $callback): bool
456
+    public function waitUntil( callable $callback ): bool
457 457
     {
458
-        $this->requireProcessIsStarted(__FUNCTION__);
459
-        $this->updateStatus(false);
458
+        $this->requireProcessIsStarted( __FUNCTION__ );
459
+        $this->updateStatus( false );
460 460
 
461
-        if (!$this->processPipes->haveReadSupport()) {
462
-            $this->stop(0);
463
-            throw new LogicException('Pass the callback to the "Process::start" method or call enableOutput to use a callback with "Process::waitUntil".');
461
+        if ( ! $this->processPipes->haveReadSupport() ) {
462
+            $this->stop( 0 );
463
+            throw new LogicException( 'Pass the callback to the "Process::start" method or call enableOutput to use a callback with "Process::waitUntil".' );
464 464
         }
465
-        $callback = $this->buildCallback($callback);
465
+        $callback = $this->buildCallback( $callback );
466 466
 
467 467
         $ready = false;
468
-        while (true) {
468
+        while ( true ) {
469 469
             $this->checkTimeout();
470 470
             $running = '\\' === \DIRECTORY_SEPARATOR ? $this->isRunning() : $this->processPipes->areOpen();
471
-            $output = $this->processPipes->readAndWrite($running, '\\' !== \DIRECTORY_SEPARATOR || !$running);
471
+            $output = $this->processPipes->readAndWrite( $running, '\\' !== \DIRECTORY_SEPARATOR || ! $running );
472 472
 
473
-            foreach ($output as $type => $data) {
474
-                if (3 !== $type) {
475
-                    $ready = $callback(self::STDOUT === $type ? self::OUT : self::ERR, $data) || $ready;
476
-                } elseif (!isset($this->fallbackStatus['signaled'])) {
477
-                    $this->fallbackStatus['exitcode'] = (int) $data;
473
+            foreach ( $output as $type => $data ) {
474
+                if ( 3 !== $type ) {
475
+                    $ready = $callback( self::STDOUT === $type ? self::OUT : self::ERR, $data ) || $ready;
476
+                } elseif ( ! isset( $this->fallbackStatus[ 'signaled' ] ) ) {
477
+                    $this->fallbackStatus[ 'exitcode' ] = (int)$data;
478 478
                 }
479 479
             }
480
-            if ($ready) {
480
+            if ( $ready ) {
481 481
                 return true;
482 482
             }
483
-            if (!$running) {
483
+            if ( ! $running ) {
484 484
                 return false;
485 485
             }
486 486
 
487
-            usleep(1000);
487
+            usleep( 1000 );
488 488
         }
489 489
     }
490 490
 
@@ -495,7 +495,7 @@  discard block
 block discarded – undo
495 495
      */
496 496
     public function getPid()
497 497
     {
498
-        return $this->isRunning() ? $this->processInformation['pid'] : null;
498
+        return $this->isRunning() ? $this->processInformation[ 'pid' ] : null;
499 499
     }
500 500
 
501 501
     /**
@@ -509,9 +509,9 @@  discard block
 block discarded – undo
509 509
      * @throws RuntimeException In case --enable-sigchild is activated and the process can't be killed
510 510
      * @throws RuntimeException In case of failure
511 511
      */
512
-    public function signal(int $signal)
512
+    public function signal( int $signal )
513 513
     {
514
-        $this->doSignal($signal, true);
514
+        $this->doSignal( $signal, true );
515 515
 
516 516
         return $this;
517 517
     }
@@ -526,11 +526,11 @@  discard block
 block discarded – undo
526 526
      */
527 527
     public function disableOutput()
528 528
     {
529
-        if ($this->isRunning()) {
530
-            throw new RuntimeException('Disabling output while the process is running is not possible.');
529
+        if ( $this->isRunning() ) {
530
+            throw new RuntimeException( 'Disabling output while the process is running is not possible.' );
531 531
         }
532
-        if (null !== $this->idleTimeout) {
533
-            throw new LogicException('Output can not be disabled while an idle timeout is set.');
532
+        if ( null !== $this->idleTimeout ) {
533
+            throw new LogicException( 'Output can not be disabled while an idle timeout is set.' );
534 534
         }
535 535
 
536 536
         $this->outputDisabled = true;
@@ -547,8 +547,8 @@  discard block
 block discarded – undo
547 547
      */
548 548
     public function enableOutput()
549 549
     {
550
-        if ($this->isRunning()) {
551
-            throw new RuntimeException('Enabling output while the process is running is not possible.');
550
+        if ( $this->isRunning() ) {
551
+            throw new RuntimeException( 'Enabling output while the process is running is not possible.' );
552 552
         }
553 553
 
554 554
         $this->outputDisabled = false;
@@ -576,9 +576,9 @@  discard block
 block discarded – undo
576 576
      */
577 577
     public function getOutput()
578 578
     {
579
-        $this->readPipesForOutput(__FUNCTION__);
579
+        $this->readPipesForOutput( __FUNCTION__ );
580 580
 
581
-        if (false === $ret = stream_get_contents($this->stdout, -1, 0)) {
581
+        if ( false === $ret = stream_get_contents( $this->stdout, -1, 0 ) ) {
582 582
             return '';
583 583
         }
584 584
 
@@ -598,12 +598,12 @@  discard block
 block discarded – undo
598 598
      */
599 599
     public function getIncrementalOutput()
600 600
     {
601
-        $this->readPipesForOutput(__FUNCTION__);
601
+        $this->readPipesForOutput( __FUNCTION__ );
602 602
 
603
-        $latest = stream_get_contents($this->stdout, -1, $this->incrementalOutputOffset);
604
-        $this->incrementalOutputOffset = ftell($this->stdout);
603
+        $latest = stream_get_contents( $this->stdout, -1, $this->incrementalOutputOffset );
604
+        $this->incrementalOutputOffset = ftell( $this->stdout );
605 605
 
606
-        if (false === $latest) {
606
+        if ( false === $latest ) {
607 607
             return '';
608 608
         }
609 609
 
@@ -621,50 +621,50 @@  discard block
 block discarded – undo
621 621
      * @return \Generator
622 622
      */
623 623
     #[\ReturnTypeWillChange]
624
-    public function getIterator(int $flags = 0)
624
+    public function getIterator( int $flags = 0 )
625 625
     {
626
-        $this->readPipesForOutput(__FUNCTION__, false);
626
+        $this->readPipesForOutput( __FUNCTION__, false );
627 627
 
628
-        $clearOutput = !(self::ITER_KEEP_OUTPUT & $flags);
629
-        $blocking = !(self::ITER_NON_BLOCKING & $flags);
630
-        $yieldOut = !(self::ITER_SKIP_OUT & $flags);
631
-        $yieldErr = !(self::ITER_SKIP_ERR & $flags);
628
+        $clearOutput = ! ( self::ITER_KEEP_OUTPUT & $flags );
629
+        $blocking = ! ( self::ITER_NON_BLOCKING & $flags );
630
+        $yieldOut = ! ( self::ITER_SKIP_OUT & $flags );
631
+        $yieldErr = ! ( self::ITER_SKIP_ERR & $flags );
632 632
 
633
-        while (null !== $this->callback || ($yieldOut && !feof($this->stdout)) || ($yieldErr && !feof($this->stderr))) {
634
-            if ($yieldOut) {
635
-                $out = stream_get_contents($this->stdout, -1, $this->incrementalOutputOffset);
633
+        while ( null !== $this->callback || ( $yieldOut && ! feof( $this->stdout ) ) || ( $yieldErr && ! feof( $this->stderr ) ) ) {
634
+            if ( $yieldOut ) {
635
+                $out = stream_get_contents( $this->stdout, -1, $this->incrementalOutputOffset );
636 636
 
637
-                if (isset($out[0])) {
638
-                    if ($clearOutput) {
637
+                if ( isset( $out[ 0 ] ) ) {
638
+                    if ( $clearOutput ) {
639 639
                         $this->clearOutput();
640 640
                     } else {
641
-                        $this->incrementalOutputOffset = ftell($this->stdout);
641
+                        $this->incrementalOutputOffset = ftell( $this->stdout );
642 642
                     }
643 643
 
644 644
                     yield self::OUT => $out;
645 645
                 }
646 646
             }
647 647
 
648
-            if ($yieldErr) {
649
-                $err = stream_get_contents($this->stderr, -1, $this->incrementalErrorOutputOffset);
648
+            if ( $yieldErr ) {
649
+                $err = stream_get_contents( $this->stderr, -1, $this->incrementalErrorOutputOffset );
650 650
 
651
-                if (isset($err[0])) {
652
-                    if ($clearOutput) {
651
+                if ( isset( $err[ 0 ] ) ) {
652
+                    if ( $clearOutput ) {
653 653
                         $this->clearErrorOutput();
654 654
                     } else {
655
-                        $this->incrementalErrorOutputOffset = ftell($this->stderr);
655
+                        $this->incrementalErrorOutputOffset = ftell( $this->stderr );
656 656
                     }
657 657
 
658 658
                     yield self::ERR => $err;
659 659
                 }
660 660
             }
661 661
 
662
-            if (!$blocking && !isset($out[0]) && !isset($err[0])) {
662
+            if ( ! $blocking && ! isset( $out[ 0 ] ) && ! isset( $err[ 0 ] ) ) {
663 663
                 yield self::OUT => '';
664 664
             }
665 665
 
666 666
             $this->checkTimeout();
667
-            $this->readPipesForOutput(__FUNCTION__, $blocking);
667
+            $this->readPipesForOutput( __FUNCTION__, $blocking );
668 668
         }
669 669
     }
670 670
 
@@ -675,8 +675,8 @@  discard block
 block discarded – undo
675 675
      */
676 676
     public function clearOutput()
677 677
     {
678
-        ftruncate($this->stdout, 0);
679
-        fseek($this->stdout, 0);
678
+        ftruncate( $this->stdout, 0 );
679
+        fseek( $this->stdout, 0 );
680 680
         $this->incrementalOutputOffset = 0;
681 681
 
682 682
         return $this;
@@ -692,9 +692,9 @@  discard block
 block discarded – undo
692 692
      */
693 693
     public function getErrorOutput()
694 694
     {
695
-        $this->readPipesForOutput(__FUNCTION__);
695
+        $this->readPipesForOutput( __FUNCTION__ );
696 696
 
697
-        if (false === $ret = stream_get_contents($this->stderr, -1, 0)) {
697
+        if ( false === $ret = stream_get_contents( $this->stderr, -1, 0 ) ) {
698 698
             return '';
699 699
         }
700 700
 
@@ -715,12 +715,12 @@  discard block
 block discarded – undo
715 715
      */
716 716
     public function getIncrementalErrorOutput()
717 717
     {
718
-        $this->readPipesForOutput(__FUNCTION__);
718
+        $this->readPipesForOutput( __FUNCTION__ );
719 719
 
720
-        $latest = stream_get_contents($this->stderr, -1, $this->incrementalErrorOutputOffset);
721
-        $this->incrementalErrorOutputOffset = ftell($this->stderr);
720
+        $latest = stream_get_contents( $this->stderr, -1, $this->incrementalErrorOutputOffset );
721
+        $this->incrementalErrorOutputOffset = ftell( $this->stderr );
722 722
 
723
-        if (false === $latest) {
723
+        if ( false === $latest ) {
724 724
             return '';
725 725
         }
726 726
 
@@ -734,8 +734,8 @@  discard block
 block discarded – undo
734 734
      */
735 735
     public function clearErrorOutput()
736 736
     {
737
-        ftruncate($this->stderr, 0);
738
-        fseek($this->stderr, 0);
737
+        ftruncate( $this->stderr, 0 );
738
+        fseek( $this->stderr, 0 );
739 739
         $this->incrementalErrorOutputOffset = 0;
740 740
 
741 741
         return $this;
@@ -748,7 +748,7 @@  discard block
 block discarded – undo
748 748
      */
749 749
     public function getExitCode()
750 750
     {
751
-        $this->updateStatus(false);
751
+        $this->updateStatus( false );
752 752
 
753 753
         return $this->exitcode;
754 754
     }
@@ -766,11 +766,11 @@  discard block
 block discarded – undo
766 766
      */
767 767
     public function getExitCodeText()
768 768
     {
769
-        if (null === $exitcode = $this->getExitCode()) {
769
+        if ( null === $exitcode = $this->getExitCode() ) {
770 770
             return null;
771 771
         }
772 772
 
773
-        return self::$exitCodes[$exitcode] ?? 'Unknown error';
773
+        return self::$exitCodes[ $exitcode ] ?? 'Unknown error';
774 774
     }
775 775
 
776 776
     /**
@@ -794,9 +794,9 @@  discard block
 block discarded – undo
794 794
      */
795 795
     public function hasBeenSignaled()
796 796
     {
797
-        $this->requireProcessIsTerminated(__FUNCTION__);
797
+        $this->requireProcessIsTerminated( __FUNCTION__ );
798 798
 
799
-        return $this->processInformation['signaled'];
799
+        return $this->processInformation[ 'signaled' ];
800 800
     }
801 801
 
802 802
     /**
@@ -811,13 +811,13 @@  discard block
 block discarded – undo
811 811
      */
812 812
     public function getTermSignal()
813 813
     {
814
-        $this->requireProcessIsTerminated(__FUNCTION__);
814
+        $this->requireProcessIsTerminated( __FUNCTION__ );
815 815
 
816
-        if ($this->isSigchildEnabled() && -1 === $this->processInformation['termsig']) {
817
-            throw new RuntimeException('This PHP has been compiled with --enable-sigchild. Term signal can not be retrieved.');
816
+        if ( $this->isSigchildEnabled() && -1 === $this->processInformation[ 'termsig' ] ) {
817
+            throw new RuntimeException( 'This PHP has been compiled with --enable-sigchild. Term signal can not be retrieved.' );
818 818
         }
819 819
 
820
-        return $this->processInformation['termsig'];
820
+        return $this->processInformation[ 'termsig' ];
821 821
     }
822 822
 
823 823
     /**
@@ -831,9 +831,9 @@  discard block
 block discarded – undo
831 831
      */
832 832
     public function hasBeenStopped()
833 833
     {
834
-        $this->requireProcessIsTerminated(__FUNCTION__);
834
+        $this->requireProcessIsTerminated( __FUNCTION__ );
835 835
 
836
-        return $this->processInformation['stopped'];
836
+        return $this->processInformation[ 'stopped' ];
837 837
     }
838 838
 
839 839
     /**
@@ -847,9 +847,9 @@  discard block
 block discarded – undo
847 847
      */
848 848
     public function getStopSignal()
849 849
     {
850
-        $this->requireProcessIsTerminated(__FUNCTION__);
850
+        $this->requireProcessIsTerminated( __FUNCTION__ );
851 851
 
852
-        return $this->processInformation['stopsig'];
852
+        return $this->processInformation[ 'stopsig' ];
853 853
     }
854 854
 
855 855
     /**
@@ -859,13 +859,13 @@  discard block
 block discarded – undo
859 859
      */
860 860
     public function isRunning()
861 861
     {
862
-        if (self::STATUS_STARTED !== $this->status) {
862
+        if ( self::STATUS_STARTED !== $this->status ) {
863 863
             return false;
864 864
         }
865 865
 
866
-        $this->updateStatus(false);
866
+        $this->updateStatus( false );
867 867
 
868
-        return $this->processInformation['running'];
868
+        return $this->processInformation[ 'running' ];
869 869
     }
870 870
 
871 871
     /**
@@ -885,7 +885,7 @@  discard block
 block discarded – undo
885 885
      */
886 886
     public function isTerminated()
887 887
     {
888
-        $this->updateStatus(false);
888
+        $this->updateStatus( false );
889 889
 
890 890
         return self::STATUS_TERMINATED == $this->status;
891 891
     }
@@ -899,7 +899,7 @@  discard block
 block discarded – undo
899 899
      */
900 900
     public function getStatus()
901 901
     {
902
-        $this->updateStatus(false);
902
+        $this->updateStatus( false );
903 903
 
904 904
         return $this->status;
905 905
     }
@@ -912,28 +912,28 @@  discard block
 block discarded – undo
912 912
      *
913 913
      * @return int|null The exit-code of the process or null if it's not running
914 914
      */
915
-    public function stop(float $timeout = 10, int $signal = null)
915
+    public function stop( float $timeout = 10, int $signal = null )
916 916
     {
917
-        $timeoutMicro = microtime(true) + $timeout;
918
-        if ($this->isRunning()) {
917
+        $timeoutMicro = microtime( true ) + $timeout;
918
+        if ( $this->isRunning() ) {
919 919
             // given SIGTERM may not be defined and that "proc_terminate" uses the constant value and not the constant itself, we use the same here
920
-            $this->doSignal(15, false);
920
+            $this->doSignal( 15, false );
921 921
             do {
922
-                usleep(1000);
923
-            } while ($this->isRunning() && microtime(true) < $timeoutMicro);
922
+                usleep( 1000 );
923
+            } while ( $this->isRunning() && microtime( true ) < $timeoutMicro );
924 924
 
925
-            if ($this->isRunning()) {
925
+            if ( $this->isRunning() ) {
926 926
                 // Avoid exception here: process is supposed to be running, but it might have stopped just
927 927
                 // after this line. In any case, let's silently discard the error, we cannot do anything.
928
-                $this->doSignal($signal ?: 9, false);
928
+                $this->doSignal( $signal ?: 9, false );
929 929
             }
930 930
         }
931 931
 
932
-        if ($this->isRunning()) {
933
-            if (isset($this->fallbackStatus['pid'])) {
934
-                unset($this->fallbackStatus['pid']);
932
+        if ( $this->isRunning() ) {
933
+            if ( isset( $this->fallbackStatus[ 'pid' ] ) ) {
934
+                unset( $this->fallbackStatus[ 'pid' ] );
935 935
 
936
-                return $this->stop(0, $signal);
936
+                return $this->stop( 0, $signal );
937 937
             }
938 938
             $this->close();
939 939
         }
@@ -946,13 +946,13 @@  discard block
 block discarded – undo
946 946
      *
947 947
      * @internal
948 948
      */
949
-    public function addOutput(string $line)
949
+    public function addOutput( string $line )
950 950
     {
951
-        $this->lastOutputTime = microtime(true);
951
+        $this->lastOutputTime = microtime( true );
952 952
 
953
-        fseek($this->stdout, 0, \SEEK_END);
954
-        fwrite($this->stdout, $line);
955
-        fseek($this->stdout, $this->incrementalOutputOffset);
953
+        fseek( $this->stdout, 0, \SEEK_END );
954
+        fwrite( $this->stdout, $line );
955
+        fseek( $this->stdout, $this->incrementalOutputOffset );
956 956
     }
957 957
 
958 958
     /**
@@ -960,13 +960,13 @@  discard block
 block discarded – undo
960 960
      *
961 961
      * @internal
962 962
      */
963
-    public function addErrorOutput(string $line)
963
+    public function addErrorOutput( string $line )
964 964
     {
965
-        $this->lastOutputTime = microtime(true);
965
+        $this->lastOutputTime = microtime( true );
966 966
 
967
-        fseek($this->stderr, 0, \SEEK_END);
968
-        fwrite($this->stderr, $line);
969
-        fseek($this->stderr, $this->incrementalErrorOutputOffset);
967
+        fseek( $this->stderr, 0, \SEEK_END );
968
+        fwrite( $this->stderr, $line );
969
+        fseek( $this->stderr, $this->incrementalErrorOutputOffset );
970 970
     }
971 971
 
972 972
     /**
@@ -986,7 +986,7 @@  discard block
 block discarded – undo
986 986
      */
987 987
     public function getCommandLine()
988 988
     {
989
-        return \is_array($this->commandline) ? implode(' ', array_map([$this, 'escapeArgument'], $this->commandline)) : $this->commandline;
989
+        return \is_array( $this->commandline ) ? implode( ' ', array_map( [ $this, 'escapeArgument' ], $this->commandline ) ) : $this->commandline;
990 990
     }
991 991
 
992 992
     /**
@@ -1018,9 +1018,9 @@  discard block
 block discarded – undo
1018 1018
      *
1019 1019
      * @throws InvalidArgumentException if the timeout is negative
1020 1020
      */
1021
-    public function setTimeout(?float $timeout)
1021
+    public function setTimeout( ?float $timeout )
1022 1022
     {
1023
-        $this->timeout = $this->validateTimeout($timeout);
1023
+        $this->timeout = $this->validateTimeout( $timeout );
1024 1024
 
1025 1025
         return $this;
1026 1026
     }
@@ -1035,13 +1035,13 @@  discard block
 block discarded – undo
1035 1035
      * @throws LogicException           if the output is disabled
1036 1036
      * @throws InvalidArgumentException if the timeout is negative
1037 1037
      */
1038
-    public function setIdleTimeout(?float $timeout)
1038
+    public function setIdleTimeout( ?float $timeout )
1039 1039
     {
1040
-        if (null !== $timeout && $this->outputDisabled) {
1041
-            throw new LogicException('Idle timeout can not be set while the output is disabled.');
1040
+        if ( null !== $timeout && $this->outputDisabled ) {
1041
+            throw new LogicException( 'Idle timeout can not be set while the output is disabled.' );
1042 1042
         }
1043 1043
 
1044
-        $this->idleTimeout = $this->validateTimeout($timeout);
1044
+        $this->idleTimeout = $this->validateTimeout( $timeout );
1045 1045
 
1046 1046
         return $this;
1047 1047
     }
@@ -1053,14 +1053,14 @@  discard block
 block discarded – undo
1053 1053
      *
1054 1054
      * @throws RuntimeException In case the TTY mode is not supported
1055 1055
      */
1056
-    public function setTty(bool $tty)
1056
+    public function setTty( bool $tty )
1057 1057
     {
1058
-        if ('\\' === \DIRECTORY_SEPARATOR && $tty) {
1059
-            throw new RuntimeException('TTY mode is not supported on Windows platform.');
1058
+        if ( '\\' === \DIRECTORY_SEPARATOR && $tty ) {
1059
+            throw new RuntimeException( 'TTY mode is not supported on Windows platform.' );
1060 1060
         }
1061 1061
 
1062
-        if ($tty && !self::isTtySupported()) {
1063
-            throw new RuntimeException('TTY mode requires /dev/tty to be read/writable.');
1062
+        if ( $tty && ! self::isTtySupported() ) {
1063
+            throw new RuntimeException( 'TTY mode requires /dev/tty to be read/writable.' );
1064 1064
         }
1065 1065
 
1066 1066
         $this->tty = $tty;
@@ -1083,7 +1083,7 @@  discard block
 block discarded – undo
1083 1083
      *
1084 1084
      * @return $this
1085 1085
      */
1086
-    public function setPty(bool $bool)
1086
+    public function setPty( bool $bool )
1087 1087
     {
1088 1088
         $this->pty = $bool;
1089 1089
 
@@ -1107,7 +1107,7 @@  discard block
 block discarded – undo
1107 1107
      */
1108 1108
     public function getWorkingDirectory()
1109 1109
     {
1110
-        if (null === $this->cwd) {
1110
+        if ( null === $this->cwd ) {
1111 1111
             // getcwd() will return false if any one of the parent directories does not have
1112 1112
             // the readable or search mode set, even if the current directory does
1113 1113
             return getcwd() ?: null;
@@ -1121,7 +1121,7 @@  discard block
 block discarded – undo
1121 1121
      *
1122 1122
      * @return $this
1123 1123
      */
1124
-    public function setWorkingDirectory(string $cwd)
1124
+    public function setWorkingDirectory( string $cwd )
1125 1125
     {
1126 1126
         $this->cwd = $cwd;
1127 1127
 
@@ -1153,11 +1153,11 @@  discard block
 block discarded – undo
1153 1153
      *
1154 1154
      * @return $this
1155 1155
      */
1156
-    public function setEnv(array $env)
1156
+    public function setEnv( array $env )
1157 1157
     {
1158 1158
         // Process can not handle env values that are arrays
1159
-        $env = array_filter($env, function ($value) {
1160
-            return !\is_array($value);
1159
+        $env = array_filter( $env, function( $value ) {
1160
+            return ! \is_array( $value );
1161 1161
         });
1162 1162
 
1163 1163
         $this->env = $env;
@@ -1186,13 +1186,13 @@  discard block
 block discarded – undo
1186 1186
      *
1187 1187
      * @throws LogicException In case the process is running
1188 1188
      */
1189
-    public function setInput($input)
1189
+    public function setInput( $input )
1190 1190
     {
1191
-        if ($this->isRunning()) {
1192
-            throw new LogicException('Input can not be set while the process is running.');
1191
+        if ( $this->isRunning() ) {
1192
+            throw new LogicException( 'Input can not be set while the process is running.' );
1193 1193
         }
1194 1194
 
1195
-        $this->input = ProcessUtils::validateInput(__METHOD__, $input);
1195
+        $this->input = ProcessUtils::validateInput( __METHOD__, $input );
1196 1196
 
1197 1197
         return $this;
1198 1198
     }
@@ -1207,20 +1207,20 @@  discard block
 block discarded – undo
1207 1207
      */
1208 1208
     public function checkTimeout()
1209 1209
     {
1210
-        if (self::STATUS_STARTED !== $this->status) {
1210
+        if ( self::STATUS_STARTED !== $this->status ) {
1211 1211
             return;
1212 1212
         }
1213 1213
 
1214
-        if (null !== $this->timeout && $this->timeout < microtime(true) - $this->starttime) {
1215
-            $this->stop(0);
1214
+        if ( null !== $this->timeout && $this->timeout < microtime( true ) - $this->starttime ) {
1215
+            $this->stop( 0 );
1216 1216
 
1217
-            throw new ProcessTimedOutException($this, ProcessTimedOutException::TYPE_GENERAL);
1217
+            throw new ProcessTimedOutException( $this, ProcessTimedOutException::TYPE_GENERAL );
1218 1218
         }
1219 1219
 
1220
-        if (null !== $this->idleTimeout && $this->idleTimeout < microtime(true) - $this->lastOutputTime) {
1221
-            $this->stop(0);
1220
+        if ( null !== $this->idleTimeout && $this->idleTimeout < microtime( true ) - $this->lastOutputTime ) {
1221
+            $this->stop( 0 );
1222 1222
 
1223
-            throw new ProcessTimedOutException($this, ProcessTimedOutException::TYPE_IDLE);
1223
+            throw new ProcessTimedOutException( $this, ProcessTimedOutException::TYPE_IDLE );
1224 1224
         }
1225 1225
     }
1226 1226
 
@@ -1229,8 +1229,8 @@  discard block
 block discarded – undo
1229 1229
      */
1230 1230
     public function getStartTime(): float
1231 1231
     {
1232
-        if (!$this->isStarted()) {
1233
-            throw new LogicException('Start time is only available after process start.');
1232
+        if ( ! $this->isStarted() ) {
1233
+            throw new LogicException( 'Start time is only available after process start.' );
1234 1234
         }
1235 1235
 
1236 1236
         return $this->starttime;
@@ -1244,21 +1244,21 @@  discard block
 block discarded – undo
1244 1244
      * Enabling the "create_new_console" option allows a subprocess to continue
1245 1245
      * to run after the main process exited, on both Windows and *nix
1246 1246
      */
1247
-    public function setOptions(array $options)
1247
+    public function setOptions( array $options )
1248 1248
     {
1249
-        if ($this->isRunning()) {
1250
-            throw new RuntimeException('Setting options while the process is running is not possible.');
1249
+        if ( $this->isRunning() ) {
1250
+            throw new RuntimeException( 'Setting options while the process is running is not possible.' );
1251 1251
         }
1252 1252
 
1253 1253
         $defaultOptions = $this->options;
1254
-        $existingOptions = ['blocking_pipes', 'create_process_group', 'create_new_console'];
1254
+        $existingOptions = [ 'blocking_pipes', 'create_process_group', 'create_new_console' ];
1255 1255
 
1256
-        foreach ($options as $key => $value) {
1257
-            if (!\in_array($key, $existingOptions)) {
1256
+        foreach ( $options as $key => $value ) {
1257
+            if ( ! \in_array( $key, $existingOptions ) ) {
1258 1258
                 $this->options = $defaultOptions;
1259
-                throw new LogicException(sprintf('Invalid option "%s" passed to "%s()". Supported options are "%s".', $key, __METHOD__, implode('", "', $existingOptions)));
1259
+                throw new LogicException( sprintf( 'Invalid option "%s" passed to "%s()". Supported options are "%s".', $key, __METHOD__, implode( '", "', $existingOptions ) ) );
1260 1260
             }
1261
-            $this->options[$key] = $value;
1261
+            $this->options[ $key ] = $value;
1262 1262
         }
1263 1263
     }
1264 1264
 
@@ -1269,8 +1269,8 @@  discard block
 block discarded – undo
1269 1269
     {
1270 1270
         static $isTtySupported;
1271 1271
 
1272
-        if (null === $isTtySupported) {
1273
-            $isTtySupported = (bool) @proc_open('echo 1 >/dev/null', [['file', '/dev/tty', 'r'], ['file', '/dev/tty', 'w'], ['file', '/dev/tty', 'w']], $pipes);
1272
+        if ( null === $isTtySupported ) {
1273
+            $isTtySupported = (bool)@proc_open( 'echo 1 >/dev/null', [ [ 'file', '/dev/tty', 'r' ], [ 'file', '/dev/tty', 'w' ], [ 'file', '/dev/tty', 'w' ] ], $pipes );
1274 1274
         }
1275 1275
 
1276 1276
         return $isTtySupported;
@@ -1285,15 +1285,15 @@  discard block
 block discarded – undo
1285 1285
     {
1286 1286
         static $result;
1287 1287
 
1288
-        if (null !== $result) {
1288
+        if ( null !== $result ) {
1289 1289
             return $result;
1290 1290
         }
1291 1291
 
1292
-        if ('\\' === \DIRECTORY_SEPARATOR) {
1292
+        if ( '\\' === \DIRECTORY_SEPARATOR ) {
1293 1293
             return $result = false;
1294 1294
         }
1295 1295
 
1296
-        return $result = (bool) @proc_open('echo 1 >/dev/null', [['pty'], ['pty'], ['pty']], $pipes);
1296
+        return $result = (bool)@proc_open( 'echo 1 >/dev/null', [ [ 'pty' ], [ 'pty' ], [ 'pty' ] ], $pipes );
1297 1297
     }
1298 1298
 
1299 1299
     /**
@@ -1301,13 +1301,13 @@  discard block
 block discarded – undo
1301 1301
      */
1302 1302
     private function getDescriptors(): array
1303 1303
     {
1304
-        if ($this->input instanceof \Iterator) {
1304
+        if ( $this->input instanceof \Iterator ) {
1305 1305
             $this->input->rewind();
1306 1306
         }
1307
-        if ('\\' === \DIRECTORY_SEPARATOR) {
1308
-            $this->processPipes = new WindowsPipes($this->input, !$this->outputDisabled || $this->hasCallback);
1307
+        if ( '\\' === \DIRECTORY_SEPARATOR ) {
1308
+            $this->processPipes = new WindowsPipes( $this->input, ! $this->outputDisabled || $this->hasCallback );
1309 1309
         } else {
1310
-            $this->processPipes = new UnixPipes($this->isTty(), $this->isPty(), $this->input, !$this->outputDisabled || $this->hasCallback);
1310
+            $this->processPipes = new UnixPipes( $this->isTty(), $this->isPty(), $this->input, ! $this->outputDisabled || $this->hasCallback );
1311 1311
         }
1312 1312
 
1313 1313
         return $this->processPipes->getDescriptors();
@@ -1323,24 +1323,24 @@  discard block
 block discarded – undo
1323 1323
      *
1324 1324
      * @return \Closure A PHP closure
1325 1325
      */
1326
-    protected function buildCallback(callable $callback = null)
1326
+    protected function buildCallback( callable $callback = null )
1327 1327
     {
1328
-        if ($this->outputDisabled) {
1329
-            return function ($type, $data) use ($callback): bool {
1330
-                return null !== $callback && $callback($type, $data);
1328
+        if ( $this->outputDisabled ) {
1329
+            return function( $type, $data ) use ( $callback ): bool {
1330
+                return null !== $callback && $callback( $type, $data );
1331 1331
             };
1332 1332
         }
1333 1333
 
1334 1334
         $out = self::OUT;
1335 1335
 
1336
-        return function ($type, $data) use ($callback, $out): bool {
1337
-            if ($out == $type) {
1338
-                $this->addOutput($data);
1336
+        return function( $type, $data ) use ( $callback, $out ): bool {
1337
+            if ( $out == $type ) {
1338
+                $this->addOutput( $data );
1339 1339
             } else {
1340
-                $this->addErrorOutput($data);
1340
+                $this->addErrorOutput( $data );
1341 1341
             }
1342 1342
 
1343
-            return null !== $callback && $callback($type, $data);
1343
+            return null !== $callback && $callback( $type, $data );
1344 1344
         };
1345 1345
     }
1346 1346
 
@@ -1349,22 +1349,22 @@  discard block
 block discarded – undo
1349 1349
      *
1350 1350
      * @param bool $blocking Whether to use a blocking read call
1351 1351
      */
1352
-    protected function updateStatus(bool $blocking)
1352
+    protected function updateStatus( bool $blocking )
1353 1353
     {
1354
-        if (self::STATUS_STARTED !== $this->status) {
1354
+        if ( self::STATUS_STARTED !== $this->status ) {
1355 1355
             return;
1356 1356
         }
1357 1357
 
1358
-        $this->processInformation = proc_get_status($this->process);
1359
-        $running = $this->processInformation['running'];
1358
+        $this->processInformation = proc_get_status( $this->process );
1359
+        $running = $this->processInformation[ 'running' ];
1360 1360
 
1361
-        $this->readPipes($running && $blocking, '\\' !== \DIRECTORY_SEPARATOR || !$running);
1361
+        $this->readPipes( $running && $blocking, '\\' !== \DIRECTORY_SEPARATOR || ! $running );
1362 1362
 
1363
-        if ($this->fallbackStatus && $this->isSigchildEnabled()) {
1363
+        if ( $this->fallbackStatus && $this->isSigchildEnabled() ) {
1364 1364
             $this->processInformation = $this->fallbackStatus + $this->processInformation;
1365 1365
         }
1366 1366
 
1367
-        if (!$running) {
1367
+        if ( ! $running ) {
1368 1368
             $this->close();
1369 1369
         }
1370 1370
     }
@@ -1376,18 +1376,18 @@  discard block
 block discarded – undo
1376 1376
      */
1377 1377
     protected function isSigchildEnabled()
1378 1378
     {
1379
-        if (null !== self::$sigchild) {
1379
+        if ( null !== self::$sigchild ) {
1380 1380
             return self::$sigchild;
1381 1381
         }
1382 1382
 
1383
-        if (!\function_exists('phpinfo')) {
1383
+        if ( ! \function_exists( 'phpinfo' ) ) {
1384 1384
             return self::$sigchild = false;
1385 1385
         }
1386 1386
 
1387 1387
         ob_start();
1388
-        phpinfo(\INFO_GENERAL);
1388
+        phpinfo( \INFO_GENERAL );
1389 1389
 
1390
-        return self::$sigchild = str_contains(ob_get_clean(), '--enable-sigchild');
1390
+        return self::$sigchild = str_contains( ob_get_clean(), '--enable-sigchild' );
1391 1391
     }
1392 1392
 
1393 1393
     /**
@@ -1398,15 +1398,15 @@  discard block
 block discarded – undo
1398 1398
      *
1399 1399
      * @throws LogicException in case output has been disabled or process is not started
1400 1400
      */
1401
-    private function readPipesForOutput(string $caller, bool $blocking = false)
1401
+    private function readPipesForOutput( string $caller, bool $blocking = false )
1402 1402
     {
1403
-        if ($this->outputDisabled) {
1404
-            throw new LogicException('Output has been disabled.');
1403
+        if ( $this->outputDisabled ) {
1404
+            throw new LogicException( 'Output has been disabled.' );
1405 1405
         }
1406 1406
 
1407
-        $this->requireProcessIsStarted($caller);
1407
+        $this->requireProcessIsStarted( $caller );
1408 1408
 
1409
-        $this->updateStatus($blocking);
1409
+        $this->updateStatus( $blocking );
1410 1410
     }
1411 1411
 
1412 1412
     /**
@@ -1414,14 +1414,14 @@  discard block
 block discarded – undo
1414 1414
      *
1415 1415
      * @throws InvalidArgumentException if the given timeout is a negative number
1416 1416
      */
1417
-    private function validateTimeout(?float $timeout): ?float
1417
+    private function validateTimeout( ?float $timeout ): ?float
1418 1418
     {
1419
-        $timeout = (float) $timeout;
1419
+        $timeout = (float)$timeout;
1420 1420
 
1421
-        if (0.0 === $timeout) {
1421
+        if ( 0.0 === $timeout ) {
1422 1422
             $timeout = null;
1423
-        } elseif ($timeout < 0) {
1424
-            throw new InvalidArgumentException('The timeout value must be a valid positive integer or float number.');
1423
+        } elseif ( $timeout < 0 ) {
1424
+            throw new InvalidArgumentException( 'The timeout value must be a valid positive integer or float number.' );
1425 1425
         }
1426 1426
 
1427 1427
         return $timeout;
@@ -1433,16 +1433,16 @@  discard block
 block discarded – undo
1433 1433
      * @param bool $blocking Whether to use blocking calls or not
1434 1434
      * @param bool $close    Whether to close file handles or not
1435 1435
      */
1436
-    private function readPipes(bool $blocking, bool $close)
1436
+    private function readPipes( bool $blocking, bool $close )
1437 1437
     {
1438
-        $result = $this->processPipes->readAndWrite($blocking, $close);
1438
+        $result = $this->processPipes->readAndWrite( $blocking, $close );
1439 1439
 
1440 1440
         $callback = $this->callback;
1441
-        foreach ($result as $type => $data) {
1442
-            if (3 !== $type) {
1443
-                $callback(self::STDOUT === $type ? self::OUT : self::ERR, $data);
1444
-            } elseif (!isset($this->fallbackStatus['signaled'])) {
1445
-                $this->fallbackStatus['exitcode'] = (int) $data;
1441
+        foreach ( $result as $type => $data ) {
1442
+            if ( 3 !== $type ) {
1443
+                $callback( self::STDOUT === $type ? self::OUT : self::ERR, $data );
1444
+            } elseif ( ! isset( $this->fallbackStatus[ 'signaled' ] ) ) {
1445
+                $this->fallbackStatus[ 'exitcode' ] = (int)$data;
1446 1446
             }
1447 1447
         }
1448 1448
     }
@@ -1455,19 +1455,19 @@  discard block
 block discarded – undo
1455 1455
     private function close(): int
1456 1456
     {
1457 1457
         $this->processPipes->close();
1458
-        if (\is_resource($this->process)) {
1459
-            proc_close($this->process);
1458
+        if ( \is_resource( $this->process ) ) {
1459
+            proc_close( $this->process );
1460 1460
         }
1461
-        $this->exitcode = $this->processInformation['exitcode'];
1461
+        $this->exitcode = $this->processInformation[ 'exitcode' ];
1462 1462
         $this->status = self::STATUS_TERMINATED;
1463 1463
 
1464 1464
         if (-1 === $this->exitcode) {
1465
-            if ($this->processInformation['signaled'] && 0 < $this->processInformation['termsig']) {
1465
+            if ( $this->processInformation[ 'signaled' ] && 0 < $this->processInformation[ 'termsig' ] ) {
1466 1466
                 // if process has been signaled, no exitcode but a valid termsig, apply Unix convention
1467
-                $this->exitcode = 128 + $this->processInformation['termsig'];
1468
-            } elseif ($this->isSigchildEnabled()) {
1469
-                $this->processInformation['signaled'] = true;
1470
-                $this->processInformation['termsig'] = -1;
1467
+                $this->exitcode = 128 + $this->processInformation[ 'termsig' ];
1468
+            } elseif ( $this->isSigchildEnabled() ) {
1469
+                $this->processInformation[ 'signaled' ] = true;
1470
+                $this->processInformation[ 'termsig' ] = -1;
1471 1471
             }
1472 1472
         }
1473 1473
 
@@ -1487,10 +1487,10 @@  discard block
 block discarded – undo
1487 1487
         $this->starttime = null;
1488 1488
         $this->callback = null;
1489 1489
         $this->exitcode = null;
1490
-        $this->fallbackStatus = [];
1490
+        $this->fallbackStatus = [ ];
1491 1491
         $this->processInformation = null;
1492
-        $this->stdout = fopen('php://temp/maxmemory:'.(1024 * 1024), 'w+');
1493
-        $this->stderr = fopen('php://temp/maxmemory:'.(1024 * 1024), 'w+');
1492
+        $this->stdout = fopen( 'php://temp/maxmemory:' . ( 1024 * 1024 ), 'w+' );
1493
+        $this->stderr = fopen( 'php://temp/maxmemory:' . ( 1024 * 1024 ), 'w+' );
1494 1494
         $this->process = null;
1495 1495
         $this->latestSignal = null;
1496 1496
         $this->status = self::STATUS_READY;
@@ -1510,36 +1510,36 @@  discard block
 block discarded – undo
1510 1510
      * @throws RuntimeException In case --enable-sigchild is activated and the process can't be killed
1511 1511
      * @throws RuntimeException In case of failure
1512 1512
      */
1513
-    private function doSignal(int $signal, bool $throwException): bool
1513
+    private function doSignal( int $signal, bool $throwException ): bool
1514 1514
     {
1515
-        if (null === $pid = $this->getPid()) {
1516
-            if ($throwException) {
1517
-                throw new LogicException('Can not send signal on a non running process.');
1515
+        if ( null === $pid = $this->getPid() ) {
1516
+            if ( $throwException ) {
1517
+                throw new LogicException( 'Can not send signal on a non running process.' );
1518 1518
             }
1519 1519
 
1520 1520
             return false;
1521 1521
         }
1522 1522
 
1523
-        if ('\\' === \DIRECTORY_SEPARATOR) {
1524
-            exec(sprintf('taskkill /F /T /PID %d 2>&1', $pid), $output, $exitCode);
1525
-            if ($exitCode && $this->isRunning()) {
1526
-                if ($throwException) {
1527
-                    throw new RuntimeException(sprintf('Unable to kill the process (%s).', implode(' ', $output)));
1523
+        if ( '\\' === \DIRECTORY_SEPARATOR ) {
1524
+            exec( sprintf( 'taskkill /F /T /PID %d 2>&1', $pid ), $output, $exitCode );
1525
+            if ( $exitCode && $this->isRunning() ) {
1526
+                if ( $throwException ) {
1527
+                    throw new RuntimeException( sprintf( 'Unable to kill the process (%s).', implode( ' ', $output ) ) );
1528 1528
                 }
1529 1529
 
1530 1530
                 return false;
1531 1531
             }
1532 1532
         } else {
1533
-            if (!$this->isSigchildEnabled()) {
1534
-                $ok = @proc_terminate($this->process, $signal);
1535
-            } elseif (\function_exists('posix_kill')) {
1536
-                $ok = @posix_kill($pid, $signal);
1537
-            } elseif ($ok = proc_open(sprintf('kill -%d %d', $signal, $pid), [2 => ['pipe', 'w']], $pipes)) {
1538
-                $ok = false === fgets($pipes[2]);
1533
+            if ( ! $this->isSigchildEnabled() ) {
1534
+                $ok = @proc_terminate( $this->process, $signal );
1535
+            } elseif ( \function_exists( 'posix_kill' ) ) {
1536
+                $ok = @posix_kill( $pid, $signal );
1537
+            } elseif ( $ok = proc_open( sprintf( 'kill -%d %d', $signal, $pid ), [ 2 => [ 'pipe', 'w' ] ], $pipes ) ) {
1538
+                $ok = false === fgets( $pipes[ 2 ] );
1539 1539
             }
1540
-            if (!$ok) {
1541
-                if ($throwException) {
1542
-                    throw new RuntimeException(sprintf('Error while sending signal "%s".', $signal));
1540
+            if ( ! $ok ) {
1541
+                if ( $throwException ) {
1542
+                    throw new RuntimeException( sprintf( 'Error while sending signal "%s".', $signal ) );
1543 1543
                 }
1544 1544
 
1545 1545
                 return false;
@@ -1547,18 +1547,18 @@  discard block
 block discarded – undo
1547 1547
         }
1548 1548
 
1549 1549
         $this->latestSignal = $signal;
1550
-        $this->fallbackStatus['signaled'] = true;
1551
-        $this->fallbackStatus['exitcode'] = -1;
1552
-        $this->fallbackStatus['termsig'] = $this->latestSignal;
1550
+        $this->fallbackStatus[ 'signaled' ] = true;
1551
+        $this->fallbackStatus[ 'exitcode' ] = -1;
1552
+        $this->fallbackStatus[ 'termsig' ] = $this->latestSignal;
1553 1553
 
1554 1554
         return true;
1555 1555
     }
1556 1556
 
1557
-    private function prepareWindowsCommandLine(string $cmd, array &$env): string
1557
+    private function prepareWindowsCommandLine( string $cmd, array &$env ): string
1558 1558
     {
1559
-        $uid = uniqid('', true);
1559
+        $uid = uniqid( '', true );
1560 1560
         $varCount = 0;
1561
-        $varCache = [];
1561
+        $varCache = [ ];
1562 1562
         $cmd = preg_replace_callback(
1563 1563
             '/"(?:(
1564 1564
                 [^"%!^]*+
@@ -1567,34 +1567,34 @@  discard block
 block discarded – undo
1567 1567
                     [^"%!^]*+
1568 1568
                 )++
1569 1569
             ) | [^"]*+ )"/x',
1570
-            function ($m) use (&$env, &$varCache, &$varCount, $uid) {
1571
-                if (!isset($m[1])) {
1572
-                    return $m[0];
1570
+            function( $m ) use ( &$env, &$varCache, &$varCount, $uid ) {
1571
+                if ( ! isset( $m[ 1 ] ) ) {
1572
+                    return $m[ 0 ];
1573 1573
                 }
1574
-                if (isset($varCache[$m[0]])) {
1575
-                    return $varCache[$m[0]];
1574
+                if ( isset( $varCache[ $m[ 0 ] ] ) ) {
1575
+                    return $varCache[ $m[ 0 ] ];
1576 1576
                 }
1577
-                if (str_contains($value = $m[1], "\0")) {
1578
-                    $value = str_replace("\0", '?', $value);
1577
+                if ( str_contains( $value = $m[ 1 ], "\0" ) ) {
1578
+                    $value = str_replace( "\0", '?', $value );
1579 1579
                 }
1580
-                if (false === strpbrk($value, "\"%!\n")) {
1581
-                    return '"'.$value.'"';
1580
+                if ( false === strpbrk( $value, "\"%!\n" ) ) {
1581
+                    return '"' . $value . '"';
1582 1582
                 }
1583 1583
 
1584
-                $value = str_replace(['!LF!', '"^!"', '"^%"', '"^^"', '""'], ["\n", '!', '%', '^', '"'], $value);
1585
-                $value = '"'.preg_replace('/(\\\\*)"/', '$1$1\\"', $value).'"';
1586
-                $var = $uid.++$varCount;
1584
+                $value = str_replace( [ '!LF!', '"^!"', '"^%"', '"^^"', '""' ], [ "\n", '!', '%', '^', '"' ], $value );
1585
+                $value = '"' . preg_replace( '/(\\\\*)"/', '$1$1\\"', $value ) . '"';
1586
+                $var = $uid . ++$varCount;
1587 1587
 
1588
-                $env[$var] = $value;
1588
+                $env[ $var ] = $value;
1589 1589
 
1590
-                return $varCache[$m[0]] = '!'.$var.'!';
1590
+                return $varCache[ $m[ 0 ] ] = '!' . $var . '!';
1591 1591
             },
1592 1592
             $cmd
1593 1593
         );
1594 1594
 
1595
-        $cmd = 'cmd /V:ON /E:ON /D /C ('.str_replace("\n", ' ', $cmd).')';
1596
-        foreach ($this->processPipes->getFiles() as $offset => $filename) {
1597
-            $cmd .= ' '.$offset.'>"'.$filename.'"';
1595
+        $cmd = 'cmd /V:ON /E:ON /D /C (' . str_replace( "\n", ' ', $cmd ) . ')';
1596
+        foreach ( $this->processPipes->getFiles() as $offset => $filename ) {
1597
+            $cmd .= ' ' . $offset . '>"' . $filename . '"';
1598 1598
         }
1599 1599
 
1600 1600
         return $cmd;
@@ -1605,10 +1605,10 @@  discard block
 block discarded – undo
1605 1605
      *
1606 1606
      * @throws LogicException if the process has not run
1607 1607
      */
1608
-    private function requireProcessIsStarted(string $functionName)
1608
+    private function requireProcessIsStarted( string $functionName )
1609 1609
     {
1610
-        if (!$this->isStarted()) {
1611
-            throw new LogicException(sprintf('Process must be started before calling "%s()".', $functionName));
1610
+        if ( ! $this->isStarted() ) {
1611
+            throw new LogicException( sprintf( 'Process must be started before calling "%s()".', $functionName ) );
1612 1612
         }
1613 1613
     }
1614 1614
 
@@ -1617,59 +1617,59 @@  discard block
 block discarded – undo
1617 1617
      *
1618 1618
      * @throws LogicException if the process is not yet terminated
1619 1619
      */
1620
-    private function requireProcessIsTerminated(string $functionName)
1620
+    private function requireProcessIsTerminated( string $functionName )
1621 1621
     {
1622
-        if (!$this->isTerminated()) {
1623
-            throw new LogicException(sprintf('Process must be terminated before calling "%s()".', $functionName));
1622
+        if ( ! $this->isTerminated() ) {
1623
+            throw new LogicException( sprintf( 'Process must be terminated before calling "%s()".', $functionName ) );
1624 1624
         }
1625 1625
     }
1626 1626
 
1627 1627
     /**
1628 1628
      * Escapes a string to be used as a shell argument.
1629 1629
      */
1630
-    private function escapeArgument(?string $argument): string
1630
+    private function escapeArgument( ?string $argument ): string
1631 1631
     {
1632
-        if ('' === $argument || null === $argument) {
1632
+        if ( '' === $argument || null === $argument ) {
1633 1633
             return '""';
1634 1634
         }
1635
-        if ('\\' !== \DIRECTORY_SEPARATOR) {
1636
-            return "'".str_replace("'", "'\\''", $argument)."'";
1635
+        if ( '\\' !== \DIRECTORY_SEPARATOR ) {
1636
+            return "'" . str_replace( "'", "'\\''", $argument ) . "'";
1637 1637
         }
1638
-        if (str_contains($argument, "\0")) {
1639
-            $argument = str_replace("\0", '?', $argument);
1638
+        if ( str_contains( $argument, "\0" ) ) {
1639
+            $argument = str_replace( "\0", '?', $argument );
1640 1640
         }
1641
-        if (!preg_match('/[\/()%!^"<>&|\s]/', $argument)) {
1641
+        if ( ! preg_match( '/[\/()%!^"<>&|\s]/', $argument ) ) {
1642 1642
             return $argument;
1643 1643
         }
1644
-        $argument = preg_replace('/(\\\\+)$/', '$1$1', $argument);
1644
+        $argument = preg_replace( '/(\\\\+)$/', '$1$1', $argument );
1645 1645
 
1646
-        return '"'.str_replace(['"', '^', '%', '!', "\n"], ['""', '"^^"', '"^%"', '"^!"', '!LF!'], $argument).'"';
1646
+        return '"' . str_replace( [ '"', '^', '%', '!', "\n" ], [ '""', '"^^"', '"^%"', '"^!"', '!LF!' ], $argument ) . '"';
1647 1647
     }
1648 1648
 
1649
-    private function replacePlaceholders(string $commandline, array $env)
1649
+    private function replacePlaceholders( string $commandline, array $env )
1650 1650
     {
1651
-        return preg_replace_callback('/"\$\{:([_a-zA-Z]++[_a-zA-Z0-9]*+)\}"/', function ($matches) use ($commandline, $env) {
1652
-            if (!isset($env[$matches[1]]) || false === $env[$matches[1]]) {
1653
-                throw new InvalidArgumentException(sprintf('Command line is missing a value for parameter "%s": ', $matches[1]).$commandline);
1651
+        return preg_replace_callback( '/"\$\{:([_a-zA-Z]++[_a-zA-Z0-9]*+)\}"/', function( $matches ) use ( $commandline, $env ) {
1652
+            if ( ! isset( $env[ $matches[ 1 ] ] ) || false === $env[ $matches[ 1 ] ] ) {
1653
+                throw new InvalidArgumentException( sprintf( 'Command line is missing a value for parameter "%s": ', $matches[ 1 ] ) . $commandline );
1654 1654
             }
1655 1655
 
1656
-            return $this->escapeArgument($env[$matches[1]]);
1657
-        }, $commandline);
1656
+            return $this->escapeArgument( $env[ $matches[ 1 ] ] );
1657
+        }, $commandline );
1658 1658
     }
1659 1659
 
1660 1660
     private function getDefaultEnv(): array
1661 1661
     {
1662
-        $env = [];
1662
+        $env = [ ];
1663 1663
 
1664
-        foreach ($_SERVER as $k => $v) {
1665
-            if (\is_string($v) && false !== $v = getenv($k)) {
1666
-                $env[$k] = $v;
1664
+        foreach ( $_SERVER as $k => $v ) {
1665
+            if ( \is_string( $v ) && false !== $v = getenv( $k ) ) {
1666
+                $env[ $k ] = $v;
1667 1667
             }
1668 1668
         }
1669 1669
 
1670
-        foreach ($_ENV as $k => $v) {
1671
-            if (\is_string($v)) {
1672
-                $env[$k] = $v;
1670
+        foreach ( $_ENV as $k => $v ) {
1671
+            if ( \is_string( $v ) ) {
1672
+                $env[ $k ] = $v;
1673 1673
             }
1674 1674
         }
1675 1675
 
Please login to merge, or discard this patch.
Braces   +62 added lines, -124 removed lines patch added patch discarded remove patch
@@ -28,8 +28,7 @@  discard block
 block discarded – undo
28 28
  * @author Fabien Potencier <[email protected]>
29 29
  * @author Romain Neutron <[email protected]>
30 30
  */
31
-class Process implements \IteratorAggregate
32
-{
31
+class Process implements \IteratorAggregate {
33 32
     public const ERR = 'err';
34 33
     public const OUT = 'out';
35 34
 
@@ -138,8 +137,7 @@  discard block
 block discarded – undo
138 137
      *
139 138
      * @throws LogicException When proc_open is not installed
140 139
      */
141
-    public function __construct(array $command, string $cwd = null, array $env = null, $input = null, ?float $timeout = 60)
142
-    {
140
+    public function __construct(array $command, string $cwd = null, array $env = null, $input = null, ?float $timeout = 60) {
143 141
         if (!\function_exists('proc_open')) {
144 142
             throw new LogicException('The Process class relies on proc_open, which is not available on your PHP installation.');
145 143
         }
@@ -187,8 +185,7 @@  discard block
 block discarded – undo
187 185
      *
188 186
      * @throws LogicException When proc_open is not installed
189 187
      */
190
-    public static function fromShellCommandline(string $command, string $cwd = null, array $env = null, $input = null, ?float $timeout = 60)
191
-    {
188
+    public static function fromShellCommandline(string $command, string $cwd = null, array $env = null, $input = null, ?float $timeout = 60) {
192 189
         $process = new static([], $cwd, $env, $input, $timeout);
193 190
         $process->commandline = $command;
194 191
 
@@ -198,18 +195,15 @@  discard block
 block discarded – undo
198 195
     /**
199 196
      * @return array
200 197
      */
201
-    public function __sleep()
202
-    {
198
+    public function __sleep() {
203 199
         throw new \BadMethodCallException('Cannot serialize '.__CLASS__);
204 200
     }
205 201
 
206
-    public function __wakeup()
207
-    {
202
+    public function __wakeup() {
208 203
         throw new \BadMethodCallException('Cannot unserialize '.__CLASS__);
209 204
     }
210 205
 
211
-    public function __destruct()
212
-    {
206
+    public function __destruct() {
213 207
         if ($this->options['create_new_console'] ?? false) {
214 208
             $this->processPipes->close();
215 209
         } else {
@@ -217,8 +211,7 @@  discard block
 block discarded – undo
217 211
         }
218 212
     }
219 213
 
220
-    public function __clone()
221
-    {
214
+    public function __clone() {
222 215
         $this->resetProcessData();
223 216
     }
224 217
 
@@ -292,8 +285,7 @@  discard block
 block discarded – undo
292 285
      * @throws RuntimeException When process is already running
293 286
      * @throws LogicException   In case a callback is provided and output has been disabled
294 287
      */
295
-    public function start(callable $callback = null, array $env = [])
296
-    {
288
+    public function start(callable $callback = null, array $env = []) {
297 289
         if ($this->isRunning()) {
298 290
             throw new RuntimeException('Process is already running.');
299 291
         }
@@ -410,8 +402,7 @@  discard block
 block discarded – undo
410 402
      * @throws ProcessSignaledException When process stopped after receiving signal
411 403
      * @throws LogicException           When process is not yet started
412 404
      */
413
-    public function wait(callable $callback = null)
414
-    {
405
+    public function wait(callable $callback = null) {
415 406
         $this->requireProcessIsStarted(__FUNCTION__);
416 407
 
417 408
         $this->updateStatus(false);
@@ -493,8 +484,7 @@  discard block
 block discarded – undo
493 484
      *
494 485
      * @return int|null The process id if running, null otherwise
495 486
      */
496
-    public function getPid()
497
-    {
487
+    public function getPid() {
498 488
         return $this->isRunning() ? $this->processInformation['pid'] : null;
499 489
     }
500 490
 
@@ -509,8 +499,7 @@  discard block
 block discarded – undo
509 499
      * @throws RuntimeException In case --enable-sigchild is activated and the process can't be killed
510 500
      * @throws RuntimeException In case of failure
511 501
      */
512
-    public function signal(int $signal)
513
-    {
502
+    public function signal(int $signal) {
514 503
         $this->doSignal($signal, true);
515 504
 
516 505
         return $this;
@@ -524,8 +513,7 @@  discard block
 block discarded – undo
524 513
      * @throws RuntimeException In case the process is already running
525 514
      * @throws LogicException   if an idle timeout is set
526 515
      */
527
-    public function disableOutput()
528
-    {
516
+    public function disableOutput() {
529 517
         if ($this->isRunning()) {
530 518
             throw new RuntimeException('Disabling output while the process is running is not possible.');
531 519
         }
@@ -545,8 +533,7 @@  discard block
 block discarded – undo
545 533
      *
546 534
      * @throws RuntimeException In case the process is already running
547 535
      */
548
-    public function enableOutput()
549
-    {
536
+    public function enableOutput() {
550 537
         if ($this->isRunning()) {
551 538
             throw new RuntimeException('Enabling output while the process is running is not possible.');
552 539
         }
@@ -561,8 +548,7 @@  discard block
 block discarded – undo
561 548
      *
562 549
      * @return bool
563 550
      */
564
-    public function isOutputDisabled()
565
-    {
551
+    public function isOutputDisabled() {
566 552
         return $this->outputDisabled;
567 553
     }
568 554
 
@@ -574,8 +560,7 @@  discard block
 block discarded – undo
574 560
      * @throws LogicException in case the output has been disabled
575 561
      * @throws LogicException In case the process is not started
576 562
      */
577
-    public function getOutput()
578
-    {
563
+    public function getOutput() {
579 564
         $this->readPipesForOutput(__FUNCTION__);
580 565
 
581 566
         if (false === $ret = stream_get_contents($this->stdout, -1, 0)) {
@@ -596,8 +581,7 @@  discard block
 block discarded – undo
596 581
      * @throws LogicException in case the output has been disabled
597 582
      * @throws LogicException In case the process is not started
598 583
      */
599
-    public function getIncrementalOutput()
600
-    {
584
+    public function getIncrementalOutput() {
601 585
         $this->readPipesForOutput(__FUNCTION__);
602 586
 
603 587
         $latest = stream_get_contents($this->stdout, -1, $this->incrementalOutputOffset);
@@ -621,8 +605,7 @@  discard block
 block discarded – undo
621 605
      * @return \Generator
622 606
      */
623 607
     #[\ReturnTypeWillChange]
624
-    public function getIterator(int $flags = 0)
625
-    {
608
+    public function getIterator(int $flags = 0) {
626 609
         $this->readPipesForOutput(__FUNCTION__, false);
627 610
 
628 611
         $clearOutput = !(self::ITER_KEEP_OUTPUT & $flags);
@@ -673,8 +656,7 @@  discard block
 block discarded – undo
673 656
      *
674 657
      * @return $this
675 658
      */
676
-    public function clearOutput()
677
-    {
659
+    public function clearOutput() {
678 660
         ftruncate($this->stdout, 0);
679 661
         fseek($this->stdout, 0);
680 662
         $this->incrementalOutputOffset = 0;
@@ -690,8 +672,7 @@  discard block
 block discarded – undo
690 672
      * @throws LogicException in case the output has been disabled
691 673
      * @throws LogicException In case the process is not started
692 674
      */
693
-    public function getErrorOutput()
694
-    {
675
+    public function getErrorOutput() {
695 676
         $this->readPipesForOutput(__FUNCTION__);
696 677
 
697 678
         if (false === $ret = stream_get_contents($this->stderr, -1, 0)) {
@@ -713,8 +694,7 @@  discard block
 block discarded – undo
713 694
      * @throws LogicException in case the output has been disabled
714 695
      * @throws LogicException In case the process is not started
715 696
      */
716
-    public function getIncrementalErrorOutput()
717
-    {
697
+    public function getIncrementalErrorOutput() {
718 698
         $this->readPipesForOutput(__FUNCTION__);
719 699
 
720 700
         $latest = stream_get_contents($this->stderr, -1, $this->incrementalErrorOutputOffset);
@@ -732,8 +712,7 @@  discard block
 block discarded – undo
732 712
      *
733 713
      * @return $this
734 714
      */
735
-    public function clearErrorOutput()
736
-    {
715
+    public function clearErrorOutput() {
737 716
         ftruncate($this->stderr, 0);
738 717
         fseek($this->stderr, 0);
739 718
         $this->incrementalErrorOutputOffset = 0;
@@ -746,8 +725,7 @@  discard block
 block discarded – undo
746 725
      *
747 726
      * @return int|null The exit status code, null if the Process is not terminated
748 727
      */
749
-    public function getExitCode()
750
-    {
728
+    public function getExitCode() {
751 729
         $this->updateStatus(false);
752 730
 
753 731
         return $this->exitcode;
@@ -764,8 +742,7 @@  discard block
 block discarded – undo
764 742
      * @see http://tldp.org/LDP/abs/html/exitcodes.html
765 743
      * @see http://en.wikipedia.org/wiki/Unix_signal
766 744
      */
767
-    public function getExitCodeText()
768
-    {
745
+    public function getExitCodeText() {
769 746
         if (null === $exitcode = $this->getExitCode()) {
770 747
             return null;
771 748
         }
@@ -778,8 +755,7 @@  discard block
 block discarded – undo
778 755
      *
779 756
      * @return bool true if the process ended successfully, false otherwise
780 757
      */
781
-    public function isSuccessful()
782
-    {
758
+    public function isSuccessful() {
783 759
         return 0 === $this->getExitCode();
784 760
     }
785 761
 
@@ -792,8 +768,7 @@  discard block
 block discarded – undo
792 768
      *
793 769
      * @throws LogicException In case the process is not terminated
794 770
      */
795
-    public function hasBeenSignaled()
796
-    {
771
+    public function hasBeenSignaled() {
797 772
         $this->requireProcessIsTerminated(__FUNCTION__);
798 773
 
799 774
         return $this->processInformation['signaled'];
@@ -809,8 +784,7 @@  discard block
 block discarded – undo
809 784
      * @throws RuntimeException In case --enable-sigchild is activated
810 785
      * @throws LogicException   In case the process is not terminated
811 786
      */
812
-    public function getTermSignal()
813
-    {
787
+    public function getTermSignal() {
814 788
         $this->requireProcessIsTerminated(__FUNCTION__);
815 789
 
816 790
         if ($this->isSigchildEnabled() && -1 === $this->processInformation['termsig']) {
@@ -829,8 +803,7 @@  discard block
 block discarded – undo
829 803
      *
830 804
      * @throws LogicException In case the process is not terminated
831 805
      */
832
-    public function hasBeenStopped()
833
-    {
806
+    public function hasBeenStopped() {
834 807
         $this->requireProcessIsTerminated(__FUNCTION__);
835 808
 
836 809
         return $this->processInformation['stopped'];
@@ -845,8 +818,7 @@  discard block
 block discarded – undo
845 818
      *
846 819
      * @throws LogicException In case the process is not terminated
847 820
      */
848
-    public function getStopSignal()
849
-    {
821
+    public function getStopSignal() {
850 822
         $this->requireProcessIsTerminated(__FUNCTION__);
851 823
 
852 824
         return $this->processInformation['stopsig'];
@@ -857,8 +829,7 @@  discard block
 block discarded – undo
857 829
      *
858 830
      * @return bool true if the process is currently running, false otherwise
859 831
      */
860
-    public function isRunning()
861
-    {
832
+    public function isRunning() {
862 833
         if (self::STATUS_STARTED !== $this->status) {
863 834
             return false;
864 835
         }
@@ -873,8 +844,7 @@  discard block
 block discarded – undo
873 844
      *
874 845
      * @return bool true if status is ready, false otherwise
875 846
      */
876
-    public function isStarted()
877
-    {
847
+    public function isStarted() {
878 848
         return self::STATUS_READY != $this->status;
879 849
     }
880 850
 
@@ -883,8 +853,7 @@  discard block
 block discarded – undo
883 853
      *
884 854
      * @return bool true if process is terminated, false otherwise
885 855
      */
886
-    public function isTerminated()
887
-    {
856
+    public function isTerminated() {
888 857
         $this->updateStatus(false);
889 858
 
890 859
         return self::STATUS_TERMINATED == $this->status;
@@ -897,8 +866,7 @@  discard block
 block discarded – undo
897 866
      *
898 867
      * @return string The current process status
899 868
      */
900
-    public function getStatus()
901
-    {
869
+    public function getStatus() {
902 870
         $this->updateStatus(false);
903 871
 
904 872
         return $this->status;
@@ -912,8 +880,7 @@  discard block
 block discarded – undo
912 880
      *
913 881
      * @return int|null The exit-code of the process or null if it's not running
914 882
      */
915
-    public function stop(float $timeout = 10, int $signal = null)
916
-    {
883
+    public function stop(float $timeout = 10, int $signal = null) {
917 884
         $timeoutMicro = microtime(true) + $timeout;
918 885
         if ($this->isRunning()) {
919 886
             // given SIGTERM may not be defined and that "proc_terminate" uses the constant value and not the constant itself, we use the same here
@@ -946,8 +913,7 @@  discard block
 block discarded – undo
946 913
      *
947 914
      * @internal
948 915
      */
949
-    public function addOutput(string $line)
950
-    {
916
+    public function addOutput(string $line) {
951 917
         $this->lastOutputTime = microtime(true);
952 918
 
953 919
         fseek($this->stdout, 0, \SEEK_END);
@@ -960,8 +926,7 @@  discard block
 block discarded – undo
960 926
      *
961 927
      * @internal
962 928
      */
963
-    public function addErrorOutput(string $line)
964
-    {
929
+    public function addErrorOutput(string $line) {
965 930
         $this->lastOutputTime = microtime(true);
966 931
 
967 932
         fseek($this->stderr, 0, \SEEK_END);
@@ -984,8 +949,7 @@  discard block
 block discarded – undo
984 949
      *
985 950
      * @return string The command to execute
986 951
      */
987
-    public function getCommandLine()
988
-    {
952
+    public function getCommandLine() {
989 953
         return \is_array($this->commandline) ? implode(' ', array_map([$this, 'escapeArgument'], $this->commandline)) : $this->commandline;
990 954
     }
991 955
 
@@ -994,8 +958,7 @@  discard block
 block discarded – undo
994 958
      *
995 959
      * @return float|null The timeout in seconds or null if it's disabled
996 960
      */
997
-    public function getTimeout()
998
-    {
961
+    public function getTimeout() {
999 962
         return $this->timeout;
1000 963
     }
1001 964
 
@@ -1004,8 +967,7 @@  discard block
 block discarded – undo
1004 967
      *
1005 968
      * @return float|null The timeout in seconds or null if it's disabled
1006 969
      */
1007
-    public function getIdleTimeout()
1008
-    {
970
+    public function getIdleTimeout() {
1009 971
         return $this->idleTimeout;
1010 972
     }
1011 973
 
@@ -1018,8 +980,7 @@  discard block
 block discarded – undo
1018 980
      *
1019 981
      * @throws InvalidArgumentException if the timeout is negative
1020 982
      */
1021
-    public function setTimeout(?float $timeout)
1022
-    {
983
+    public function setTimeout(?float $timeout) {
1023 984
         $this->timeout = $this->validateTimeout($timeout);
1024 985
 
1025 986
         return $this;
@@ -1035,8 +996,7 @@  discard block
 block discarded – undo
1035 996
      * @throws LogicException           if the output is disabled
1036 997
      * @throws InvalidArgumentException if the timeout is negative
1037 998
      */
1038
-    public function setIdleTimeout(?float $timeout)
1039
-    {
999
+    public function setIdleTimeout(?float $timeout) {
1040 1000
         if (null !== $timeout && $this->outputDisabled) {
1041 1001
             throw new LogicException('Idle timeout can not be set while the output is disabled.');
1042 1002
         }
@@ -1053,8 +1013,7 @@  discard block
 block discarded – undo
1053 1013
      *
1054 1014
      * @throws RuntimeException In case the TTY mode is not supported
1055 1015
      */
1056
-    public function setTty(bool $tty)
1057
-    {
1016
+    public function setTty(bool $tty) {
1058 1017
         if ('\\' === \DIRECTORY_SEPARATOR && $tty) {
1059 1018
             throw new RuntimeException('TTY mode is not supported on Windows platform.');
1060 1019
         }
@@ -1073,8 +1032,7 @@  discard block
 block discarded – undo
1073 1032
      *
1074 1033
      * @return bool true if the TTY mode is enabled, false otherwise
1075 1034
      */
1076
-    public function isTty()
1077
-    {
1035
+    public function isTty() {
1078 1036
         return $this->tty;
1079 1037
     }
1080 1038
 
@@ -1083,8 +1041,7 @@  discard block
 block discarded – undo
1083 1041
      *
1084 1042
      * @return $this
1085 1043
      */
1086
-    public function setPty(bool $bool)
1087
-    {
1044
+    public function setPty(bool $bool) {
1088 1045
         $this->pty = $bool;
1089 1046
 
1090 1047
         return $this;
@@ -1095,8 +1052,7 @@  discard block
 block discarded – undo
1095 1052
      *
1096 1053
      * @return bool
1097 1054
      */
1098
-    public function isPty()
1099
-    {
1055
+    public function isPty() {
1100 1056
         return $this->pty;
1101 1057
     }
1102 1058
 
@@ -1105,8 +1061,7 @@  discard block
 block discarded – undo
1105 1061
      *
1106 1062
      * @return string|null The current working directory or null on failure
1107 1063
      */
1108
-    public function getWorkingDirectory()
1109
-    {
1064
+    public function getWorkingDirectory() {
1110 1065
         if (null === $this->cwd) {
1111 1066
             // getcwd() will return false if any one of the parent directories does not have
1112 1067
             // the readable or search mode set, even if the current directory does
@@ -1121,8 +1076,7 @@  discard block
 block discarded – undo
1121 1076
      *
1122 1077
      * @return $this
1123 1078
      */
1124
-    public function setWorkingDirectory(string $cwd)
1125
-    {
1079
+    public function setWorkingDirectory(string $cwd) {
1126 1080
         $this->cwd = $cwd;
1127 1081
 
1128 1082
         return $this;
@@ -1133,8 +1087,7 @@  discard block
 block discarded – undo
1133 1087
      *
1134 1088
      * @return array The current environment variables
1135 1089
      */
1136
-    public function getEnv()
1137
-    {
1090
+    public function getEnv() {
1138 1091
         return $this->env;
1139 1092
     }
1140 1093
 
@@ -1153,8 +1106,7 @@  discard block
 block discarded – undo
1153 1106
      *
1154 1107
      * @return $this
1155 1108
      */
1156
-    public function setEnv(array $env)
1157
-    {
1109
+    public function setEnv(array $env) {
1158 1110
         // Process can not handle env values that are arrays
1159 1111
         $env = array_filter($env, function ($value) {
1160 1112
             return !\is_array($value);
@@ -1170,8 +1122,7 @@  discard block
 block discarded – undo
1170 1122
      *
1171 1123
      * @return resource|string|\Iterator|null The Process input
1172 1124
      */
1173
-    public function getInput()
1174
-    {
1125
+    public function getInput() {
1175 1126
         return $this->input;
1176 1127
     }
1177 1128
 
@@ -1186,8 +1137,7 @@  discard block
 block discarded – undo
1186 1137
      *
1187 1138
      * @throws LogicException In case the process is running
1188 1139
      */
1189
-    public function setInput($input)
1190
-    {
1140
+    public function setInput($input) {
1191 1141
         if ($this->isRunning()) {
1192 1142
             throw new LogicException('Input can not be set while the process is running.');
1193 1143
         }
@@ -1205,8 +1155,7 @@  discard block
 block discarded – undo
1205 1155
      *
1206 1156
      * @throws ProcessTimedOutException In case the timeout was reached
1207 1157
      */
1208
-    public function checkTimeout()
1209
-    {
1158
+    public function checkTimeout() {
1210 1159
         if (self::STATUS_STARTED !== $this->status) {
1211 1160
             return;
1212 1161
         }
@@ -1244,8 +1193,7 @@  discard block
 block discarded – undo
1244 1193
      * Enabling the "create_new_console" option allows a subprocess to continue
1245 1194
      * to run after the main process exited, on both Windows and *nix
1246 1195
      */
1247
-    public function setOptions(array $options)
1248
-    {
1196
+    public function setOptions(array $options) {
1249 1197
         if ($this->isRunning()) {
1250 1198
             throw new RuntimeException('Setting options while the process is running is not possible.');
1251 1199
         }
@@ -1281,8 +1229,7 @@  discard block
 block discarded – undo
1281 1229
      *
1282 1230
      * @return bool
1283 1231
      */
1284
-    public static function isPtySupported()
1285
-    {
1232
+    public static function isPtySupported() {
1286 1233
         static $result;
1287 1234
 
1288 1235
         if (null !== $result) {
@@ -1323,8 +1270,7 @@  discard block
 block discarded – undo
1323 1270
      *
1324 1271
      * @return \Closure A PHP closure
1325 1272
      */
1326
-    protected function buildCallback(callable $callback = null)
1327
-    {
1273
+    protected function buildCallback(callable $callback = null) {
1328 1274
         if ($this->outputDisabled) {
1329 1275
             return function ($type, $data) use ($callback): bool {
1330 1276
                 return null !== $callback && $callback($type, $data);
@@ -1349,8 +1295,7 @@  discard block
 block discarded – undo
1349 1295
      *
1350 1296
      * @param bool $blocking Whether to use a blocking read call
1351 1297
      */
1352
-    protected function updateStatus(bool $blocking)
1353
-    {
1298
+    protected function updateStatus(bool $blocking) {
1354 1299
         if (self::STATUS_STARTED !== $this->status) {
1355 1300
             return;
1356 1301
         }
@@ -1374,8 +1319,7 @@  discard block
 block discarded – undo
1374 1319
      *
1375 1320
      * @return bool
1376 1321
      */
1377
-    protected function isSigchildEnabled()
1378
-    {
1322
+    protected function isSigchildEnabled() {
1379 1323
         if (null !== self::$sigchild) {
1380 1324
             return self::$sigchild;
1381 1325
         }
@@ -1398,8 +1342,7 @@  discard block
 block discarded – undo
1398 1342
      *
1399 1343
      * @throws LogicException in case output has been disabled or process is not started
1400 1344
      */
1401
-    private function readPipesForOutput(string $caller, bool $blocking = false)
1402
-    {
1345
+    private function readPipesForOutput(string $caller, bool $blocking = false) {
1403 1346
         if ($this->outputDisabled) {
1404 1347
             throw new LogicException('Output has been disabled.');
1405 1348
         }
@@ -1433,8 +1376,7 @@  discard block
 block discarded – undo
1433 1376
      * @param bool $blocking Whether to use blocking calls or not
1434 1377
      * @param bool $close    Whether to close file handles or not
1435 1378
      */
1436
-    private function readPipes(bool $blocking, bool $close)
1437
-    {
1379
+    private function readPipes(bool $blocking, bool $close) {
1438 1380
         $result = $this->processPipes->readAndWrite($blocking, $close);
1439 1381
 
1440 1382
         $callback = $this->callback;
@@ -1482,8 +1424,7 @@  discard block
 block discarded – undo
1482 1424
     /**
1483 1425
      * Resets data related to the latest run of the process.
1484 1426
      */
1485
-    private function resetProcessData()
1486
-    {
1427
+    private function resetProcessData() {
1487 1428
         $this->starttime = null;
1488 1429
         $this->callback = null;
1489 1430
         $this->exitcode = null;
@@ -1605,8 +1546,7 @@  discard block
 block discarded – undo
1605 1546
      *
1606 1547
      * @throws LogicException if the process has not run
1607 1548
      */
1608
-    private function requireProcessIsStarted(string $functionName)
1609
-    {
1549
+    private function requireProcessIsStarted(string $functionName) {
1610 1550
         if (!$this->isStarted()) {
1611 1551
             throw new LogicException(sprintf('Process must be started before calling "%s()".', $functionName));
1612 1552
         }
@@ -1617,8 +1557,7 @@  discard block
 block discarded – undo
1617 1557
      *
1618 1558
      * @throws LogicException if the process is not yet terminated
1619 1559
      */
1620
-    private function requireProcessIsTerminated(string $functionName)
1621
-    {
1560
+    private function requireProcessIsTerminated(string $functionName) {
1622 1561
         if (!$this->isTerminated()) {
1623 1562
             throw new LogicException(sprintf('Process must be terminated before calling "%s()".', $functionName));
1624 1563
         }
@@ -1646,8 +1585,7 @@  discard block
 block discarded – undo
1646 1585
         return '"'.str_replace(['"', '^', '%', '!', "\n"], ['""', '"^^"', '"^%"', '"^!"', '!LF!'], $argument).'"';
1647 1586
     }
1648 1587
 
1649
-    private function replacePlaceholders(string $commandline, array $env)
1650
-    {
1588
+    private function replacePlaceholders(string $commandline, array $env) {
1651 1589
         return preg_replace_callback('/"\$\{:([_a-zA-Z]++[_a-zA-Z0-9]*+)\}"/', function ($matches) use ($commandline, $env) {
1652 1590
             if (!isset($env[$matches[1]]) || false === $env[$matches[1]]) {
1653 1591
                 throw new InvalidArgumentException(sprintf('Command line is missing a value for parameter "%s": ', $matches[1]).$commandline);
Please login to merge, or discard this patch.
vendor/symfony/polyfill-php80/bootstrap.php 2 patches
Indentation   +9 added lines, -9 removed lines patch added patch discarded remove patch
@@ -12,31 +12,31 @@
 block discarded – undo
12 12
 use Symfony\Polyfill\Php80 as p;
13 13
 
14 14
 if (\PHP_VERSION_ID >= 80000) {
15
-    return;
15
+	return;
16 16
 }
17 17
 
18 18
 if (!defined('FILTER_VALIDATE_BOOL') && defined('FILTER_VALIDATE_BOOLEAN')) {
19
-    define('FILTER_VALIDATE_BOOL', \FILTER_VALIDATE_BOOLEAN);
19
+	define('FILTER_VALIDATE_BOOL', \FILTER_VALIDATE_BOOLEAN);
20 20
 }
21 21
 
22 22
 if (!function_exists('fdiv')) {
23
-    function fdiv(float $num1, float $num2): float { return p\Php80::fdiv($num1, $num2); }
23
+	function fdiv(float $num1, float $num2): float { return p\Php80::fdiv($num1, $num2); }
24 24
 }
25 25
 if (!function_exists('preg_last_error_msg')) {
26
-    function preg_last_error_msg(): string { return p\Php80::preg_last_error_msg(); }
26
+	function preg_last_error_msg(): string { return p\Php80::preg_last_error_msg(); }
27 27
 }
28 28
 if (!function_exists('str_contains')) {
29
-    function str_contains(?string $haystack, ?string $needle): bool { return p\Php80::str_contains($haystack ?? '', $needle ?? ''); }
29
+	function str_contains(?string $haystack, ?string $needle): bool { return p\Php80::str_contains($haystack ?? '', $needle ?? ''); }
30 30
 }
31 31
 if (!function_exists('str_starts_with')) {
32
-    function str_starts_with(?string $haystack, ?string $needle): bool { return p\Php80::str_starts_with($haystack ?? '', $needle ?? ''); }
32
+	function str_starts_with(?string $haystack, ?string $needle): bool { return p\Php80::str_starts_with($haystack ?? '', $needle ?? ''); }
33 33
 }
34 34
 if (!function_exists('str_ends_with')) {
35
-    function str_ends_with(?string $haystack, ?string $needle): bool { return p\Php80::str_ends_with($haystack ?? '', $needle ?? ''); }
35
+	function str_ends_with(?string $haystack, ?string $needle): bool { return p\Php80::str_ends_with($haystack ?? '', $needle ?? ''); }
36 36
 }
37 37
 if (!function_exists('get_debug_type')) {
38
-    function get_debug_type($value): string { return p\Php80::get_debug_type($value); }
38
+	function get_debug_type($value): string { return p\Php80::get_debug_type($value); }
39 39
 }
40 40
 if (!function_exists('get_resource_id')) {
41
-    function get_resource_id($resource): int { return p\Php80::get_resource_id($resource); }
41
+	function get_resource_id($resource): int { return p\Php80::get_resource_id($resource); }
42 42
 }
Please login to merge, or discard this patch.
Spacing   +16 added lines, -16 removed lines patch added patch discarded remove patch
@@ -11,32 +11,32 @@
 block discarded – undo
11 11
 
12 12
 use Symfony\Polyfill\Php80 as p;
13 13
 
14
-if (\PHP_VERSION_ID >= 80000) {
14
+if ( \PHP_VERSION_ID >= 80000 ) {
15 15
     return;
16 16
 }
17 17
 
18
-if (!defined('FILTER_VALIDATE_BOOL') && defined('FILTER_VALIDATE_BOOLEAN')) {
19
-    define('FILTER_VALIDATE_BOOL', \FILTER_VALIDATE_BOOLEAN);
18
+if ( ! defined( 'FILTER_VALIDATE_BOOL' ) && defined( 'FILTER_VALIDATE_BOOLEAN' ) ) {
19
+    define( 'FILTER_VALIDATE_BOOL', \FILTER_VALIDATE_BOOLEAN );
20 20
 }
21 21
 
22
-if (!function_exists('fdiv')) {
23
-    function fdiv(float $num1, float $num2): float { return p\Php80::fdiv($num1, $num2); }
22
+if ( ! function_exists( 'fdiv' ) ) {
23
+    function fdiv( float $num1, float $num2 ): float { return p\Php80::fdiv( $num1, $num2 ); }
24 24
 }
25
-if (!function_exists('preg_last_error_msg')) {
25
+if ( ! function_exists( 'preg_last_error_msg' ) ) {
26 26
     function preg_last_error_msg(): string { return p\Php80::preg_last_error_msg(); }
27 27
 }
28
-if (!function_exists('str_contains')) {
29
-    function str_contains(?string $haystack, ?string $needle): bool { return p\Php80::str_contains($haystack ?? '', $needle ?? ''); }
28
+if ( ! function_exists( 'str_contains' ) ) {
29
+    function str_contains( ?string $haystack, ?string $needle ): bool { return p\Php80::str_contains( $haystack ?? '', $needle ?? '' ); }
30 30
 }
31
-if (!function_exists('str_starts_with')) {
32
-    function str_starts_with(?string $haystack, ?string $needle): bool { return p\Php80::str_starts_with($haystack ?? '', $needle ?? ''); }
31
+if ( ! function_exists( 'str_starts_with' ) ) {
32
+    function str_starts_with( ?string $haystack, ?string $needle ): bool { return p\Php80::str_starts_with( $haystack ?? '', $needle ?? '' ); }
33 33
 }
34
-if (!function_exists('str_ends_with')) {
35
-    function str_ends_with(?string $haystack, ?string $needle): bool { return p\Php80::str_ends_with($haystack ?? '', $needle ?? ''); }
34
+if ( ! function_exists( 'str_ends_with' ) ) {
35
+    function str_ends_with( ?string $haystack, ?string $needle ): bool { return p\Php80::str_ends_with( $haystack ?? '', $needle ?? '' ); }
36 36
 }
37
-if (!function_exists('get_debug_type')) {
38
-    function get_debug_type($value): string { return p\Php80::get_debug_type($value); }
37
+if ( ! function_exists( 'get_debug_type' ) ) {
38
+    function get_debug_type( $value ): string { return p\Php80::get_debug_type( $value ); }
39 39
 }
40
-if (!function_exists('get_resource_id')) {
41
-    function get_resource_id($resource): int { return p\Php80::get_resource_id($resource); }
40
+if ( ! function_exists( 'get_resource_id' ) ) {
41
+    function get_resource_id( $resource ): int { return p\Php80::get_resource_id( $resource ); }
42 42
 }
Please login to merge, or discard this patch.
vendor/symfony/polyfill-php80/Php80.php 3 patches
Indentation   +70 added lines, -70 removed lines patch added patch discarded remove patch
@@ -20,86 +20,86 @@
 block discarded – undo
20 20
  */
21 21
 final class Php80
22 22
 {
23
-    public static function fdiv(float $dividend, float $divisor): float
24
-    {
25
-        return @($dividend / $divisor);
26
-    }
23
+	public static function fdiv(float $dividend, float $divisor): float
24
+	{
25
+		return @($dividend / $divisor);
26
+	}
27 27
 
28
-    public static function get_debug_type($value): string
29
-    {
30
-        switch (true) {
31
-            case null === $value: return 'null';
32
-            case \is_bool($value): return 'bool';
33
-            case \is_string($value): return 'string';
34
-            case \is_array($value): return 'array';
35
-            case \is_int($value): return 'int';
36
-            case \is_float($value): return 'float';
37
-            case \is_object($value): break;
38
-            case $value instanceof \__PHP_Incomplete_Class: return '__PHP_Incomplete_Class';
39
-            default:
40
-                if (null === $type = @get_resource_type($value)) {
41
-                    return 'unknown';
42
-                }
28
+	public static function get_debug_type($value): string
29
+	{
30
+		switch (true) {
31
+			case null === $value: return 'null';
32
+			case \is_bool($value): return 'bool';
33
+			case \is_string($value): return 'string';
34
+			case \is_array($value): return 'array';
35
+			case \is_int($value): return 'int';
36
+			case \is_float($value): return 'float';
37
+			case \is_object($value): break;
38
+			case $value instanceof \__PHP_Incomplete_Class: return '__PHP_Incomplete_Class';
39
+			default:
40
+				if (null === $type = @get_resource_type($value)) {
41
+					return 'unknown';
42
+				}
43 43
 
44
-                if ('Unknown' === $type) {
45
-                    $type = 'closed';
46
-                }
44
+				if ('Unknown' === $type) {
45
+					$type = 'closed';
46
+				}
47 47
 
48
-                return "resource ($type)";
49
-        }
48
+				return "resource ($type)";
49
+		}
50 50
 
51
-        $class = \get_class($value);
51
+		$class = \get_class($value);
52 52
 
53
-        if (false === strpos($class, '@')) {
54
-            return $class;
55
-        }
53
+		if (false === strpos($class, '@')) {
54
+			return $class;
55
+		}
56 56
 
57
-        return (get_parent_class($class) ?: key(class_implements($class)) ?: 'class').'@anonymous';
58
-    }
57
+		return (get_parent_class($class) ?: key(class_implements($class)) ?: 'class').'@anonymous';
58
+	}
59 59
 
60
-    public static function get_resource_id($res): int
61
-    {
62
-        if (!\is_resource($res) && null === @get_resource_type($res)) {
63
-            throw new \TypeError(sprintf('Argument 1 passed to get_resource_id() must be of the type resource, %s given', get_debug_type($res)));
64
-        }
60
+	public static function get_resource_id($res): int
61
+	{
62
+		if (!\is_resource($res) && null === @get_resource_type($res)) {
63
+			throw new \TypeError(sprintf('Argument 1 passed to get_resource_id() must be of the type resource, %s given', get_debug_type($res)));
64
+		}
65 65
 
66
-        return (int) $res;
67
-    }
66
+		return (int) $res;
67
+	}
68 68
 
69
-    public static function preg_last_error_msg(): string
70
-    {
71
-        switch (preg_last_error()) {
72
-            case \PREG_INTERNAL_ERROR:
73
-                return 'Internal error';
74
-            case \PREG_BAD_UTF8_ERROR:
75
-                return 'Malformed UTF-8 characters, possibly incorrectly encoded';
76
-            case \PREG_BAD_UTF8_OFFSET_ERROR:
77
-                return 'The offset did not correspond to the beginning of a valid UTF-8 code point';
78
-            case \PREG_BACKTRACK_LIMIT_ERROR:
79
-                return 'Backtrack limit exhausted';
80
-            case \PREG_RECURSION_LIMIT_ERROR:
81
-                return 'Recursion limit exhausted';
82
-            case \PREG_JIT_STACKLIMIT_ERROR:
83
-                return 'JIT stack limit exhausted';
84
-            case \PREG_NO_ERROR:
85
-                return 'No error';
86
-            default:
87
-                return 'Unknown error';
88
-        }
89
-    }
69
+	public static function preg_last_error_msg(): string
70
+	{
71
+		switch (preg_last_error()) {
72
+			case \PREG_INTERNAL_ERROR:
73
+				return 'Internal error';
74
+			case \PREG_BAD_UTF8_ERROR:
75
+				return 'Malformed UTF-8 characters, possibly incorrectly encoded';
76
+			case \PREG_BAD_UTF8_OFFSET_ERROR:
77
+				return 'The offset did not correspond to the beginning of a valid UTF-8 code point';
78
+			case \PREG_BACKTRACK_LIMIT_ERROR:
79
+				return 'Backtrack limit exhausted';
80
+			case \PREG_RECURSION_LIMIT_ERROR:
81
+				return 'Recursion limit exhausted';
82
+			case \PREG_JIT_STACKLIMIT_ERROR:
83
+				return 'JIT stack limit exhausted';
84
+			case \PREG_NO_ERROR:
85
+				return 'No error';
86
+			default:
87
+				return 'Unknown error';
88
+		}
89
+	}
90 90
 
91
-    public static function str_contains(string $haystack, string $needle): bool
92
-    {
93
-        return '' === $needle || false !== strpos($haystack, $needle);
94
-    }
91
+	public static function str_contains(string $haystack, string $needle): bool
92
+	{
93
+		return '' === $needle || false !== strpos($haystack, $needle);
94
+	}
95 95
 
96
-    public static function str_starts_with(string $haystack, string $needle): bool
97
-    {
98
-        return 0 === strncmp($haystack, $needle, \strlen($needle));
99
-    }
96
+	public static function str_starts_with(string $haystack, string $needle): bool
97
+	{
98
+		return 0 === strncmp($haystack, $needle, \strlen($needle));
99
+	}
100 100
 
101
-    public static function str_ends_with(string $haystack, string $needle): bool
102
-    {
103
-        return '' === $needle || ('' !== $haystack && 0 === substr_compare($haystack, $needle, -\strlen($needle)));
104
-    }
101
+	public static function str_ends_with(string $haystack, string $needle): bool
102
+	{
103
+		return '' === $needle || ('' !== $haystack && 0 === substr_compare($haystack, $needle, -\strlen($needle)));
104
+	}
105 105
 }
Please login to merge, or discard this patch.
Spacing   +26 added lines, -26 removed lines patch added patch discarded remove patch
@@ -20,55 +20,55 @@  discard block
 block discarded – undo
20 20
  */
21 21
 final class Php80
22 22
 {
23
-    public static function fdiv(float $dividend, float $divisor): float
23
+    public static function fdiv( float $dividend, float $divisor ): float
24 24
     {
25
-        return @($dividend / $divisor);
25
+        return @( $dividend / $divisor );
26 26
     }
27 27
 
28
-    public static function get_debug_type($value): string
28
+    public static function get_debug_type( $value ): string
29 29
     {
30
-        switch (true) {
30
+        switch ( true ) {
31 31
             case null === $value: return 'null';
32
-            case \is_bool($value): return 'bool';
33
-            case \is_string($value): return 'string';
34
-            case \is_array($value): return 'array';
35
-            case \is_int($value): return 'int';
36
-            case \is_float($value): return 'float';
37
-            case \is_object($value): break;
32
+            case \is_bool( $value ): return 'bool';
33
+            case \is_string( $value ): return 'string';
34
+            case \is_array( $value ): return 'array';
35
+            case \is_int( $value ): return 'int';
36
+            case \is_float( $value ): return 'float';
37
+            case \is_object( $value ): break;
38 38
             case $value instanceof \__PHP_Incomplete_Class: return '__PHP_Incomplete_Class';
39 39
             default:
40
-                if (null === $type = @get_resource_type($value)) {
40
+                if ( null === $type = @get_resource_type( $value ) ) {
41 41
                     return 'unknown';
42 42
                 }
43 43
 
44
-                if ('Unknown' === $type) {
44
+                if ( 'Unknown' === $type ) {
45 45
                     $type = 'closed';
46 46
                 }
47 47
 
48 48
                 return "resource ($type)";
49 49
         }
50 50
 
51
-        $class = \get_class($value);
51
+        $class = \get_class( $value );
52 52
 
53
-        if (false === strpos($class, '@')) {
53
+        if ( false === strpos( $class, '@' ) ) {
54 54
             return $class;
55 55
         }
56 56
 
57
-        return (get_parent_class($class) ?: key(class_implements($class)) ?: 'class').'@anonymous';
57
+        return ( get_parent_class( $class ) ?: key( class_implements( $class ) ) ?: 'class' ) . '@anonymous';
58 58
     }
59 59
 
60
-    public static function get_resource_id($res): int
60
+    public static function get_resource_id( $res ): int
61 61
     {
62
-        if (!\is_resource($res) && null === @get_resource_type($res)) {
63
-            throw new \TypeError(sprintf('Argument 1 passed to get_resource_id() must be of the type resource, %s given', get_debug_type($res)));
62
+        if ( ! \is_resource( $res ) && null === @get_resource_type( $res ) ) {
63
+            throw new \TypeError( sprintf( 'Argument 1 passed to get_resource_id() must be of the type resource, %s given', get_debug_type( $res ) ) );
64 64
         }
65 65
 
66
-        return (int) $res;
66
+        return (int)$res;
67 67
     }
68 68
 
69 69
     public static function preg_last_error_msg(): string
70 70
     {
71
-        switch (preg_last_error()) {
71
+        switch ( preg_last_error() ) {
72 72
             case \PREG_INTERNAL_ERROR:
73 73
                 return 'Internal error';
74 74
             case \PREG_BAD_UTF8_ERROR:
@@ -88,18 +88,18 @@  discard block
 block discarded – undo
88 88
         }
89 89
     }
90 90
 
91
-    public static function str_contains(string $haystack, string $needle): bool
91
+    public static function str_contains( string $haystack, string $needle ): bool
92 92
     {
93
-        return '' === $needle || false !== strpos($haystack, $needle);
93
+        return '' === $needle || false !== strpos( $haystack, $needle );
94 94
     }
95 95
 
96
-    public static function str_starts_with(string $haystack, string $needle): bool
96
+    public static function str_starts_with( string $haystack, string $needle ): bool
97 97
     {
98
-        return 0 === strncmp($haystack, $needle, \strlen($needle));
98
+        return 0 === strncmp( $haystack, $needle, \strlen( $needle ) );
99 99
     }
100 100
 
101
-    public static function str_ends_with(string $haystack, string $needle): bool
101
+    public static function str_ends_with( string $haystack, string $needle ): bool
102 102
     {
103
-        return '' === $needle || ('' !== $haystack && 0 === substr_compare($haystack, $needle, -\strlen($needle)));
103
+        return '' === $needle || ( '' !== $haystack && 0 === substr_compare( $haystack, $needle, -\strlen( $needle ) ) );
104 104
     }
105 105
 }
Please login to merge, or discard this patch.
Braces   +1 added lines, -2 removed lines patch added patch discarded remove patch
@@ -18,8 +18,7 @@
 block discarded – undo
18 18
  *
19 19
  * @internal
20 20
  */
21
-final class Php80
22
-{
21
+final class Php80 {
23 22
     public static function fdiv(float $dividend, float $divisor): float
24 23
     {
25 24
         return @($dividend / $divisor);
Please login to merge, or discard this patch.
vendor/symfony/polyfill-php80/Resources/stubs/Stringable.php 3 patches
Indentation   +7 added lines, -7 removed lines patch added patch discarded remove patch
@@ -1,11 +1,11 @@
 block discarded – undo
1 1
 <?php
2 2
 
3 3
 if (\PHP_VERSION_ID < 80000) {
4
-    interface Stringable
5
-    {
6
-        /**
7
-         * @return string
8
-         */
9
-        public function __toString();
10
-    }
4
+	interface Stringable
5
+	{
6
+		/**
7
+		 * @return string
8
+		 */
9
+		public function __toString();
10
+	}
11 11
 }
Please login to merge, or discard this patch.
Spacing   +1 added lines, -1 removed lines patch added patch discarded remove patch
@@ -1,6 +1,6 @@
 block discarded – undo
1 1
 <?php
2 2
 
3
-if (\PHP_VERSION_ID < 80000) {
3
+if ( \PHP_VERSION_ID < 80000 ) {
4 4
     interface Stringable
5 5
     {
6 6
         /**
Please login to merge, or discard this patch.
Braces   +1 added lines, -2 removed lines patch added patch discarded remove patch
@@ -1,8 +1,7 @@
 block discarded – undo
1 1
 <?php
2 2
 
3 3
 if (\PHP_VERSION_ID < 80000) {
4
-    interface Stringable
5
-    {
4
+    interface Stringable {
6 5
         /**
7 6
          * @return string
8 7
          */
Please login to merge, or discard this patch.
vendor/symfony/polyfill-php80/Resources/stubs/ValueError.php 1 patch
Braces   +1 added lines, -2 removed lines patch added patch discarded remove patch
@@ -1,5 +1,4 @@
 block discarded – undo
1 1
 <?php
2 2
 
3
-class ValueError extends Error
4
-{
3
+class ValueError extends Error {
5 4
 }
Please login to merge, or discard this patch.
vendor/symfony/polyfill-php80/Resources/stubs/UnhandledMatchError.php 1 patch
Braces   +1 added lines, -2 removed lines patch added patch discarded remove patch
@@ -1,5 +1,4 @@
 block discarded – undo
1 1
 <?php
2 2
 
3
-class UnhandledMatchError extends Error
4
-{
3
+class UnhandledMatchError extends Error {
5 4
 }
Please login to merge, or discard this patch.
vendor/symfony/polyfill-php80/Resources/stubs/Attribute.php 3 patches
Indentation   +14 added lines, -14 removed lines patch added patch discarded remove patch
@@ -3,20 +3,20 @@
 block discarded – undo
3 3
 #[Attribute(Attribute::TARGET_CLASS)]
4 4
 final class Attribute
5 5
 {
6
-    public const TARGET_CLASS = 1;
7
-    public const TARGET_FUNCTION = 2;
8
-    public const TARGET_METHOD = 4;
9
-    public const TARGET_PROPERTY = 8;
10
-    public const TARGET_CLASS_CONSTANT = 16;
11
-    public const TARGET_PARAMETER = 32;
12
-    public const TARGET_ALL = 63;
13
-    public const IS_REPEATABLE = 64;
6
+	public const TARGET_CLASS = 1;
7
+	public const TARGET_FUNCTION = 2;
8
+	public const TARGET_METHOD = 4;
9
+	public const TARGET_PROPERTY = 8;
10
+	public const TARGET_CLASS_CONSTANT = 16;
11
+	public const TARGET_PARAMETER = 32;
12
+	public const TARGET_ALL = 63;
13
+	public const IS_REPEATABLE = 64;
14 14
 
15
-    /** @var int */
16
-    public $flags;
15
+	/** @var int */
16
+	public $flags;
17 17
 
18
-    public function __construct(int $flags = self::TARGET_ALL)
19
-    {
20
-        $this->flags = $flags;
21
-    }
18
+	public function __construct(int $flags = self::TARGET_ALL)
19
+	{
20
+		$this->flags = $flags;
21
+	}
22 22
 }
Please login to merge, or discard this patch.
Spacing   +1 added lines, -1 removed lines patch added patch discarded remove patch
@@ -15,7 +15,7 @@
 block discarded – undo
15 15
     /** @var int */
16 16
     public $flags;
17 17
 
18
-    public function __construct(int $flags = self::TARGET_ALL)
18
+    public function __construct( int $flags = self::TARGET_ALL )
19 19
     {
20 20
         $this->flags = $flags;
21 21
     }
Please login to merge, or discard this patch.
Braces   +2 added lines, -4 removed lines patch added patch discarded remove patch
@@ -1,8 +1,7 @@  discard block
 block discarded – undo
1 1
 <?php
2 2
 
3 3
 #[Attribute(Attribute::TARGET_CLASS)]
4
-final class Attribute
5
-{
4
+final class Attribute {
6 5
     public const TARGET_CLASS = 1;
7 6
     public const TARGET_FUNCTION = 2;
8 7
     public const TARGET_METHOD = 4;
@@ -15,8 +14,7 @@  discard block
 block discarded – undo
15 14
     /** @var int */
16 15
     public $flags;
17 16
 
18
-    public function __construct(int $flags = self::TARGET_ALL)
19
-    {
17
+    public function __construct(int $flags = self::TARGET_ALL) {
20 18
         $this->flags = $flags;
21 19
     }
22 20
 }
Please login to merge, or discard this patch.
vendor/symfony/polyfill-php73/bootstrap.php 2 patches
Indentation   +7 added lines, -7 removed lines patch added patch discarded remove patch
@@ -12,20 +12,20 @@
 block discarded – undo
12 12
 use Symfony\Polyfill\Php73 as p;
13 13
 
14 14
 if (\PHP_VERSION_ID >= 70300) {
15
-    return;
15
+	return;
16 16
 }
17 17
 
18 18
 if (!function_exists('is_countable')) {
19
-    function is_countable($value) { return is_array($value) || $value instanceof Countable || $value instanceof ResourceBundle || $value instanceof SimpleXmlElement; }
19
+	function is_countable($value) { return is_array($value) || $value instanceof Countable || $value instanceof ResourceBundle || $value instanceof SimpleXmlElement; }
20 20
 }
21 21
 if (!function_exists('hrtime')) {
22
-    require_once __DIR__.'/Php73.php';
23
-    p\Php73::$startAt = (int) microtime(true);
24
-    function hrtime($as_number = false) { return p\Php73::hrtime($as_number); }
22
+	require_once __DIR__.'/Php73.php';
23
+	p\Php73::$startAt = (int) microtime(true);
24
+	function hrtime($as_number = false) { return p\Php73::hrtime($as_number); }
25 25
 }
26 26
 if (!function_exists('array_key_first')) {
27
-    function array_key_first(array $array) { foreach ($array as $key => $value) { return $key; } }
27
+	function array_key_first(array $array) { foreach ($array as $key => $value) { return $key; } }
28 28
 }
29 29
 if (!function_exists('array_key_last')) {
30
-    function array_key_last(array $array) { return key(array_slice($array, -1, 1, true)); }
30
+	function array_key_last(array $array) { return key(array_slice($array, -1, 1, true)); }
31 31
 }
Please login to merge, or discard this patch.
Spacing   +11 added lines, -11 removed lines patch added patch discarded remove patch
@@ -11,21 +11,21 @@
 block discarded – undo
11 11
 
12 12
 use Symfony\Polyfill\Php73 as p;
13 13
 
14
-if (\PHP_VERSION_ID >= 70300) {
14
+if ( \PHP_VERSION_ID >= 70300 ) {
15 15
     return;
16 16
 }
17 17
 
18
-if (!function_exists('is_countable')) {
19
-    function is_countable($value) { return is_array($value) || $value instanceof Countable || $value instanceof ResourceBundle || $value instanceof SimpleXmlElement; }
18
+if ( ! function_exists( 'is_countable' ) ) {
19
+    function is_countable( $value ) { return is_array( $value ) || $value instanceof Countable || $value instanceof ResourceBundle || $value instanceof SimpleXmlElement; }
20 20
 }
21
-if (!function_exists('hrtime')) {
22
-    require_once __DIR__.'/Php73.php';
23
-    p\Php73::$startAt = (int) microtime(true);
24
-    function hrtime($as_number = false) { return p\Php73::hrtime($as_number); }
21
+if ( ! function_exists( 'hrtime' ) ) {
22
+    require_once __DIR__ . '/Php73.php';
23
+    p\Php73::$startAt = (int)microtime( true );
24
+    function hrtime( $as_number = false ) { return p\Php73::hrtime( $as_number ); }
25 25
 }
26
-if (!function_exists('array_key_first')) {
27
-    function array_key_first(array $array) { foreach ($array as $key => $value) { return $key; } }
26
+if ( ! function_exists( 'array_key_first' ) ) {
27
+    function array_key_first( array $array ) { foreach ( $array as $key => $value ) { return $key; } }
28 28
 }
29
-if (!function_exists('array_key_last')) {
30
-    function array_key_last(array $array) { return key(array_slice($array, -1, 1, true)); }
29
+if ( ! function_exists( 'array_key_last' ) ) {
30
+    function array_key_last( array $array ) { return key( array_slice( $array, -1, 1, true ) ); }
31 31
 }
Please login to merge, or discard this patch.