clue/term-react
ReactPHP-powered interactive terminal for PHP. Read keypresses and line input from STDIN without blocking, work with streams and events, and build responsive CLI apps that react to user input in real time.
Start by installing via Composer: composer require clue/term-react. This package provides a streaming ANSI terminal emulator for ReactPHP, ideal for building interactive CLI tools, remote shell proxies, or TTY-aware WebSocket servers. Your first use case is likely capturing and processing terminal input/output in async PHP — for example, acting as a middleware layer between a WebSocket client and an underlying process. Initialize the emulator with a sink (e.g., a WriteStream) to receive emitted ANSI sequences:
use Clue\React\Term\Term;
use React\Stream\ThroughStream;
$sink = new ThroughStream();
$term = new Term($sink);
// Hook up input stream (e.g., stdin or socket)
$stdin->on('data', [$term, 'input']);
// Pipe output back
$sink->pipe($stdoutOrSocket);
Check the examples/ folder in the repo for minimal working demos like echo-server.php or websocket-term.php.
Common patterns involve embedding Term in event-driven CLI or server apps:
Term to forward interactive shells to subprocesses (React\ChildProcess\Process) and handle PTY-like interactions.Ratchet\WebSocket\WsServer), converting WS messages ↔ terminal escape sequences.$sink stream to sanitize or augment output (e.g., log terminal sessions, convert colors).Term::input() via extension or composition to inject hotkeys or command shortcuts before forwarding to the sink.For scalable use, couple with React\EventLoop\Loop and a PSR-7/PSR-15-compatible HTTP/WebSocket stack (e.g., React\Http + React\Socket). Always ensure you handle backpressure by enabling流控 (setEncoding('binary'), respecting isWritable()).
$sink must be able to consume data quickly. If downstream (e.g., WebSocket) is slow, pipe via ThroughStream + Buffer to avoid memory bloat.Term is stateless-by-default. If reconnecting clients (e.g., SSH over WS), you must implement your own state snapshot (e.g., save buffer + cursor state via $term->exportState() — note: this method doesn’t exist in current v1; you must subclass and track manually).script or asciinema to verify behavior.final and non-extendable — override behavior by composition: wrap Term and delegate calls, intercepting input() and sink events.exit event handlers to avoid zombie processes — Term doesn’t manage child lifecycle.ResourceStream writing to php://stderr, or use a custom sink that logs data events with timestamps.How can I help you explore Laravel packages today?