@@ -18,9 +18,8 @@ as [Streams](https://github.com/reactphp/stream).
1818 * [ EventEmitter Events] ( #eventemitter-events )
1919 * [ Methods] ( #methods )
2020 * [ Stream Properties] ( #stream-properties )
21- * [ Prepending Commands with ` exec ` ] ( #prepending-commands-with-exec )
21+ * [ Command ] ( #command )
2222 * [ Sigchild Compatibility] ( #sigchild-compatibility )
23- * [ Command Chaining] ( #command-chaining )
2423* [ Install] ( #install )
2524* [ Tests] ( #tests )
2625* [ License] ( #license )
@@ -102,15 +101,106 @@ $process->stdin->close();
102101For more details, see the
103102[ ` DuplexStreamInterface ` ] ( https://github.com/reactphp/stream#duplexstreaminterface ) .
104103
105- ### Prepending Commands with ` exec `
104+ ### Command
106105
107- Symfony pull request [ #5759 ] ( https://github.com/symfony/symfony/issues/5759 )
108- documents a caveat with the
109- [ Program Execution] ( http://php.net/manual/en/book.exec.php ) extension. PHP will
110- launch processes via ` sh ` , which obfuscates the underlying process' PID and
111- complicates signaling (our process becomes a child of ` sh ` ). As a work-around,
112- prepend the command string with ` exec ` , which will cause the ` sh ` process to be
113- replaced by our process.
106+ The ` Process ` class allows you to pass any kind of command line string:
107+
108+ ``` php
109+ $process = new Process('echo test');
110+ ```
111+
112+ By default, PHP will launch processes by wrapping the given command line string
113+ in a ` sh ` command, so that the above example will actually execute
114+ ` sh -c echo test ` under the hood.
115+
116+ This is a very useful feature because it does not only allow you to pass single
117+ commands, but actually allows you to pass any kind of shell command line and
118+ launch multiple sub-commands using command chains (with ` && ` , ` || ` , ` ; ` and
119+ others) and allows you to redirect STDIO streams (with ` 2>&1 ` and family).
120+ This can be used to pass complete command lines and receive the resulting STDIO
121+ streams from the wrapping shell command like this:
122+
123+ ``` php
124+ $process = new Process('echo run && demo || echo failed');
125+ ```
126+
127+ In other words, the underlying shell is responsible for managing this command
128+ line and launching the individual sub-commands and connecting their STDIO
129+ streams as appropriate.
130+ This implies that the ` Process ` class will only receive the resulting STDIO
131+ streams from the wrapping shell, which will thus contain the complete
132+ input/output with no way to discern the input/output of single sub-commands.
133+
134+ If you want to discern the output of single sub-commands, you may want to
135+ implement some higher-level protocol logic, such as printing an explicit
136+ boundary between each sub-command like this:
137+
138+ ``` php
139+ $process = new Process('cat first && echo --- && cat second');
140+ ```
141+
142+ As an alternative, considering launching one process at a time and listening on
143+ its ` exit ` event to conditionally start the next process in the chain.
144+ This will give you an opportunity to configure the subsequent process I/O streams:
145+
146+ ``` php
147+ $first = new Process('cat first');
148+ $first->start($loop);
149+
150+ $first->on('exit', function () use ($loop) {
151+ $second = new Process('cat second');
152+ $second->start($loop);
153+ });
154+ ```
155+
156+ Keep in mind that PHP uses the shell wrapper for ALL command lines.
157+ While this may seem reasonable for more complex command lines, this actually
158+ also applies to running the most simple single command:
159+
160+ ``` php
161+ $process = new Process('yes');
162+ ```
163+
164+ This will actually spawn a command hierarchy similar to this:
165+
166+ ```
167+ 5480 … \_ php example.php
168+ 5481 … \_ sh -c yes
169+ 5482 … \_ yes
170+ ```
171+
172+ This means that trying to get the underlying process PID or sending signals
173+ will actually target the wrapping shell, which may not be the desired result
174+ in many cases.
175+
176+ If you do not want this wrapping shell process to show up, you can simply
177+ prepend the command string with ` exec ` , which will cause the wrapping shell
178+ process to be replaced by our process:
179+
180+ ``` php
181+ $process = new Process('exec yes');
182+ ```
183+
184+ This will show a resulting command hierarchy similar to this:
185+
186+ ```
187+ 5480 … \_ php example.php
188+ 5481 … \_ yes
189+ ```
190+
191+ This means that trying to get the underlying process PID and sending signals
192+ will now target the actual command as expected.
193+
194+ Note that in this case, the command line will not be run in a wrapping shell.
195+ This implies that when using ` exec ` , there's no way to pass command lines such
196+ as those containing command chains or redirected STDIO streams.
197+
198+ As a rule of thumb, most commands will likely run just fine with the wrapping
199+ shell.
200+ If you pass a complete command line (or are unsure), you SHOULD most likely keep
201+ the wrapping shell.
202+ If you want to pass an invidual command only, you MAY want to consider
203+ prepending the command string with ` exec ` to avoid the wrapping shell.
114204
115205### Sigchild Compatibility
116206
@@ -127,15 +217,6 @@ of the actual exit code.
127217** Note:** This functionality was taken from Symfony's
128218[ Process] ( https://github.com/symfony/process ) compoment.
129219
130- ### Command Chaining
131-
132- Command chaning with ` && ` or ` ; ` , while possible with ` proc_open() ` , should not
133- be used with this component. There is currently no way to discern when each
134- process in a chain ends, which would complicate working with I/O streams. As an
135- alternative, considering launching one process at a time and listening on its
136- ` exit ` event to conditionally start the next process in the chain. This will
137- give you an opportunity to configure the subsequent process' I/O streams.
138-
139220## Install
140221
141222The recommended way to install this library is [ through Composer] ( http://getcomposer.org ) .
0 commit comments