Waits for the process to terminate.
The callback receives the type of output (out or err) and some bytes from the output in real-time while writing the standard input to the process. It allows to have feedback from the independent process during execution.
callback|null $callback A valid PHP callback:
integer The exitcode of the process
\RuntimeException When process timed out
\RuntimeException When process stopped after receiving signal
public function wait($callback = null) {
$this
->updateStatus();
$callback = $this
->buildCallback($callback);
while ($this->pipes || defined('PHP_WINDOWS_VERSION_BUILD') && $this->fileHandles) {
if (defined('PHP_WINDOWS_VERSION_BUILD') && $this->fileHandles) {
$this
->processFileHandles($callback, !$this->pipes);
}
$this
->checkTimeout();
if ($this->pipes) {
$r = $this->pipes;
$w = null;
$e = null;
// let's have a look if something changed in streams
if (false === ($n = @stream_select($r, $w, $e, 0, ceil(static::TIMEOUT_PRECISION * 1000000.0)))) {
$lastError = error_get_last();
// stream_select returns false when the `select` system call is interrupted by an incoming signal
if (isset($lastError['message']) && false === stripos($lastError['message'], 'interrupted system call')) {
$this->pipes = array();
}
continue;
}
// nothing has changed
if (0 === $n) {
continue;
}
foreach ($r as $pipe) {
$type = array_search($pipe, $this->pipes);
$data = fread($pipe, 8192);
if (strlen($data) > 0) {
// last exit code is output and caught to work around --enable-sigchild
if (3 == $type) {
$this->fallbackExitcode = (int) $data;
}
else {
call_user_func($callback, $type == 1 ? self::OUT : self::ERR, $data);
}
}
if (false === $data || feof($pipe)) {
fclose($pipe);
unset($this->pipes[$type]);
}
}
}
}
$this
->updateStatus();
if ($this->processInformation['signaled']) {
if ($this
->isSigchildEnabled()) {
throw new RuntimeException('The process has been signaled.');
}
throw new RuntimeException(sprintf('The process has been signaled with signal "%s".', $this->processInformation['termsig']));
}
$time = 0;
while ($this
->isRunning() && $time < 1000000) {
$time += 1000;
usleep(1000);
}
$exitcode = proc_close($this->process);
if ($this->processInformation['signaled']) {
if ($this
->isSigchildEnabled()) {
throw new RuntimeException('The process has been signaled.');
}
throw new RuntimeException(sprintf('The process has been signaled with signal "%s".', $this->processInformation['termsig']));
}
$this->exitcode = $this->processInformation['running'] ? $exitcode : $this->processInformation['exitcode'];
if (-1 == $this->exitcode && null !== $this->fallbackExitcode) {
$this->exitcode = $this->fallbackExitcode;
}
return $this->exitcode;
}