handle = popen($command, $mode); $this->canRead = strpos($mode, 'r') !== false; $this->canWrite = strpos($mode, 'w') !== false; if(!is_resource($this->handle)) throw new IOException('Failed to create process.'); } public function getPosition(): int { return -1; } public function getLength(): int { return -1; } public function setLength(int $length): void {} public function canRead(): bool { return $this->canRead; } public function canWrite(): bool { return $this->canWrite; } public function canSeek(): bool { return false; } public function hasTimedOut(): bool { return false; } public function isBlocking(): bool { return true; } public function isEnded(): bool { return feof($this->handle); } public function readChar(): ?string { $char = fgetc($this->handle); if($char === false) return null; return $char; } public function readLine(): ?string { return ($line = fgets($this->handle)) === false ? null : $line; } public function read(int $length): ?string { $buffer = fread($this->handle, $length); if($buffer === false) return null; return $buffer; } public function seek(int $offset, int $origin = self::START): int { throw new IOException('Cannot seek ProcessStream.'); } public function write(string $buffer, int $length = -1): void { if($length >= 0) fwrite($this->handle, $buffer, $length); else fwrite($this->handle, $buffer); } public function writeChar(string $char): void { fwrite($this->handle, $char, 1); } public function flush(): void {} public function close(): void { if(is_resource($this->handle)) { pclose($this->handle); $this->handle = null; } } }