1
1
<?php namespace kamermans \Command ;
2
-
2
+ use kamermans \Command \Stream \Handler ;
3
+
4
+ /**
5
+ * Class ProcessManager
6
+ * Starts and manages a process, handling STDIN, STDOUT and STDERR and exit status.
7
+ *
8
+ * @package kamermans\Command
9
+ */
3
10
class ProcessManager {
4
11
5
12
protected $ cmd ;
@@ -10,6 +17,12 @@ class ProcessManager {
10
17
protected $ io_writes = [];
11
18
protected $ streams = [];
12
19
20
+
21
+ /**
22
+ * ProcessManager constructor.
23
+ * @param string $cmd Full command to be run
24
+ * @param array $buffers Array of buffers to be used for STDIN, STDOUT, STDERR
25
+ */
13
26
public function __construct ($ cmd , &$ buffers )
14
27
{
15
28
if (!is_array ($ buffers )) {
@@ -21,15 +34,15 @@ public function __construct($cmd, &$buffers)
21
34
}
22
35
23
36
/**
24
- * Executes a command returning the exitcode and capturing the stdout and stderr
37
+ * Executes a command returning the exit code and capturing the stdout and stderr
25
38
*
26
39
* @param callable $callback A callback function for stdout/stderr data
27
40
* @param bool $callbacklines Call callback for each line
28
41
* @param int $buffer_size Read this many bytes at a time
29
42
* @param string $cwd Set working directory
30
43
* @param array $env Environment variables for the process
31
44
* @param array $conf Additional options for proc_open()
32
- * @return int
45
+ * @return int Process exit code
33
46
*/
34
47
public function exec ($ callback , $ callbacklines , $ buffer_size , $ cwd , $ env , $ conf )
35
48
{
@@ -79,13 +92,24 @@ public function exec($callback, $callbacklines, $buffer_size, $cwd, $env, $conf)
79
92
return $ exit_code ;
80
93
}
81
94
95
+ /**
96
+ * Checks all ready read/write handles as returned by `stream_select()` and calls the write() or read() methods
97
+ * of their corresponding Stream handler
98
+ *
99
+ * @see Writer::write()
100
+ * @see Reader::read()
101
+ *
102
+ * @param $handles
103
+ * @return bool
104
+ * @throws Exception
105
+ */
82
106
protected function doReadWrite ($ handles )
83
107
{
84
108
if ($ handles ['ready ' ] === 0 ) {
85
109
// Stream timeout; no streams ready
86
110
return false ;
87
111
} else if ($ handles ['ready ' ] === false ) {
88
- throw new \ Exception ("stream_select() failed while waiting for I/O on command " );
112
+ throw new Exception ("stream_select() failed while waiting for I/O on command " );
89
113
}
90
114
91
115
// Read from all ready streams
@@ -108,6 +132,14 @@ protected function doReadWrite($handles)
108
132
return true ;
109
133
}
110
134
135
+ /**
136
+ * Opens the process handle via `proc_open()`
137
+ *
138
+ * @param string $cwd The initial working dir for the command. This must be an absolute directory path or null.
139
+ * @param array $env An array with the environment variables for the command that will be run, or null.
140
+ * @param array $conf Additional options to pass to `proc_open()` (as the `$other_options` parameter).
141
+ * @throws Exception The command failed to start
142
+ */
111
143
protected function open ($ cwd , $ env , $ conf )
112
144
{
113
145
// Define the streams to configure for the process
@@ -120,7 +152,7 @@ protected function open($cwd, $env, $conf)
120
152
// Start the process
121
153
$ this ->handle = proc_open ($ this ->cmd , $ descriptors , $ this ->io_handles , $ cwd , $ env , $ conf );
122
154
if (!is_resource ($ this ->handle )) {
123
- throw new \ Exception ("Failed to open process handle " );
155
+ throw new Exception ("Failed to open process handle " );
124
156
}
125
157
126
158
// Set all IO handles to non-blocking mode
@@ -142,7 +174,14 @@ protected function open($cwd, $env, $conf)
142
174
];
143
175
}
144
176
145
- protected function close ($ exit_code , $ callback )
177
+ /**
178
+ * Closes the currently running process and returns the exit code.
179
+ *
180
+ * @param int $exit_code The code that the process exited with or null if unavailable
181
+ * @param callable $callback Output data callback function
182
+ * @return int Exit code
183
+ */
184
+ protected function close ($ exit_code , callable $ callback =null )
146
185
{
147
186
// Make sure all IO handles are closed
148
187
foreach ($ this ->io_handles as $ id => $ handle ) {
@@ -171,16 +210,29 @@ protected function close($exit_code, $callback)
171
210
return $ exit_code ;
172
211
}
173
212
213
+ /**
214
+ * @return bool true if STDIN buffer is available for reading
215
+ */
174
216
protected function isStdInAvailable ()
175
217
{
176
218
return $ this ->isStdInStreaming () || !empty ($ this ->buffers [Command::STDIN ]);
177
219
}
178
220
221
+ /**
222
+ * @return bool true if STDIN is a stream (false if it is a string)
223
+ */
179
224
protected function isStdInStreaming ()
180
225
{
181
226
return is_resource ($ this ->buffers [Command::STDIN ]);
182
227
}
183
228
229
+ /**
230
+ * Setup the STDIN, STDOUT and STDERR stream handlers
231
+ *
232
+ * @param callable|null $callback
233
+ * @param bool $callbacklines
234
+ * @param int $buffer_size
235
+ */
184
236
protected function setupStreams ($ callback , $ callbacklines , $ buffer_size )
185
237
{
186
238
// Prepare STDIN
@@ -253,28 +305,33 @@ protected function setupStreams($callback, $callbacklines, $buffer_size)
253
305
];
254
306
}
255
307
256
-
308
+ /**
309
+ * This function will wait until streams are ready for read/write, or a timeout has occurred, then it will
310
+ * return an array of those handles that are ready for processing.
311
+ *
312
+ * @return array
313
+ */
257
314
protected function waitForReadyHandles ()
258
315
{
259
316
// Setup streams before each iteration since they are changed by stream_select()
260
317
$ stream_select_timeout_sec = null ;
261
318
$ stream_select_timeout_usec = 200000 ;
262
319
263
- $ handles ['read ' ] = array_filter ($ this ->io_reads , 'is_resource ' );
320
+ $ handles = [
321
+ 'read ' => array_filter ($ this ->io_reads , 'is_resource ' ),
322
+ 'write ' => [],
323
+ 'except ' => [],
324
+ ];
264
325
265
326
if ($ this ->isStdInAvailable () && is_resource ($ this ->io_handles [Command::STDIN ])) {
266
327
$ handles ['write ' ] = $ this ->io_writes ;
267
- } else {
268
- $ handles ['write ' ] = [];
269
328
}
270
329
271
- $ except = [];
272
-
273
330
// This line will block until a stream is ready for input or output
274
331
$ num_ready = stream_select (
275
332
$ handles ['read ' ],
276
333
$ handles ['write ' ],
277
- $ except ,
334
+ $ handles [ ' except ' ] ,
278
335
$ stream_select_timeout_sec ,
279
336
$ stream_select_timeout_usec
280
337
);
@@ -284,6 +341,12 @@ protected function waitForReadyHandles()
284
341
return $ handles ;
285
342
}
286
343
344
+ /**
345
+ * Returns the Stream Handler (Reader/Writer) that is managing a given IO handle
346
+ *
347
+ * @param resource $handle
348
+ * @return Stream\Handler
349
+ */
287
350
protected function getStreamFromIoHandle ($ handle )
288
351
{
289
352
return $ this ->streams [array_search ($ handle , $ this ->io_handles )];
0 commit comments