timeout = $timeoutSeconds; return $this; } public function withIdleTimeout(int $idleTimeoutSeconds): static { $this->idleTimeout = $idleTimeoutSeconds; return $this; } public function withEnvironment(array $environment): static { $this->environment = $environment; return $this; } public function withAdditionalPathLocation(string $directoryPath): static { $this->additionalProgramDirectories[] = $directoryPath; return $this; } public function runCapturingAllOutput(array $args): string { $output = ''; $callable = function ($data) use (&$output) { $output .= $data; }; $this->runWithoutOutputCallbacks($args, $callable, $callable); return $output; } public function runCapturingStdErr(array $args): string { $err = ''; $this->runWithoutOutputCallbacks($args, fn() => '', function ($data) use (&$err) { $err .= $data; }); return $err; } public function runWithoutOutputCallbacks(array $args, callable $stdOutCallback = null, callable $stdErrCallback = null): int { $process = $this->startProcess($args); foreach ($process as $type => $data) { if ($type === $process::ERR) { if ($stdErrCallback) { $stdErrCallback($data); } } else { if ($stdOutCallback) { $stdOutCallback($data); } } } return $process->getExitCode() ?? 1; } /** * @throws \Exception */ public function ensureFound(): void { $this->resolveProgramPath(); } public function isFound(): bool { try { $this->ensureFound(); return true; } catch (\Exception $exception) { return false; } } protected function startProcess(array $args): Process { $programPath = $this->resolveProgramPath(); $process = new Process([$programPath, ...$args], null, $this->environment); $process->setTimeout($this->timeout); $process->setIdleTimeout($this->idleTimeout); $process->start(); return $process; } protected function resolveProgramPath(): string { $executableFinder = new ExecutableFinder(); $path = $executableFinder->find($this->program, $this->defaultPath, $this->additionalProgramDirectories); if (is_null($path) || !is_file($path)) { throw new \Exception("Could not locate \"{$this->program}\" program."); } return $path; } }