public function start()
{
if (null !== $this->delayed) {
throw new StatusError('The process has already been started.');
}
$this->delayed = new Delayed();
$fd = [['pipe', 'r'], ['pipe', 'w'], ['pipe', 'a'], ['pipe', 'w']];
$nd = 0 === strncasecmp(PHP_OS, 'WIN', 3) ? 'NUL' : '/dev/null';
$command = sprintf('(%s) 3>%s; code=$?; echo $code >&3; exit $code', $this->command, $nd);
$this->process = proc_open($command, $fd, $pipes, $this->cwd ?: null, $this->env ?: null, $this->options);
if (!is_resource($this->process)) {
throw new ProcessException('Could not start process.');
}
$this->oid = getmypid();
$status = proc_get_status($this->process);
if (!$status) {
proc_close($this->process);
$this->process = null;
throw new ProcessException('Could not get process status.');
}
$this->pid = $status['pid'];
$this->stdin = new WritablePipe($pipes[0]);
$this->stdout = new ReadablePipe($pipes[1]);
$this->stderr = new ReadablePipe($pipes[2]);
$stream = $pipes[3];
stream_set_blocking($stream, 0);
$this->poll = Loop\poll($stream, function ($resource) {
if (!is_resource($resource) || feof($resource)) {
$this->close($resource);
$this->delayed->reject(new ProcessException('Process ended unexpectedly.'));
} else {
$code = fread($resource, 1);
$this->close($resource);
if (!strlen($code) || !is_numeric($code)) {
$this->delayed->reject(new ProcessException('Process ended without providing a status code.'));
} else {
$this->delayed->resolve((int) $code);
}
}
$this->poll->free();
});
}