Re: Re: [PHP DEV] [Discussion] Native terminal helpers for PHP CLI

From: Date: Fri, 18 Sep 2026 07:35:26 +0000
Subject: Re: Re: [PHP DEV] [Discussion] Native terminal helpers for PHP CLI
References: 1  Groups: php.internals 
Request: Send a blank email to internals+get-132531@lists.php.net to get a copy of this message
On Fri, Sep 18, 2026, at 04:19, Pratik Bhujel wrote: > Hi Tim, hi internals, > > Thank you for the detailed feedback. Your observations on namespace grouping, instance handles, > unbacked enums, and standard library conventions made complete sense. > > Instead of just replying in theory, I took the time over the past couple of days to step back, > study how other ecosystems handle terminal interfaces, and rebuild the extension accordingly. > Version 0.8.0 is now released with that exact architecture. > > To answer your question regarding the domain problem: > > The primary issue is that PHP CLI currently lacks native primitives for non-canonical raw > terminal mode and single keypress reading. Modern interactive CLI tools in userland (such as Laravel > Prompts, Symfony Console, and interactive tools) want to deliver rich experiences like searchable > selection menus, autocomplete, multi-choice checkboxes, spinners, and hidden password prompts. > > Today, userland libraries face two severe problems: > > 1. On Linux and macOS, packages work around the missing primitives by executing the external > stty tool using proc_open or exec. However, inside minimal Docker containers (such as Alpine or slim > environments where stty is absent) or environments where process execution functions are restricted, > interactive CLI tools fail completely. > > 2. On Windows, stty does not exist. Windows uses the Win32 Console API.. Because PHP has lacked > these primitives, interactive CLI packages on Windows either crash or fall back to crude text > prompts where the user must type choices manually and hit Enter. Reading password input without > displaying characters on Windows even required distributing separate helper executables. > > 3. When a script exits unexpectedly or an unhandled exception occurs while the terminal is in > raw mode, the user shell is left corrupted with disabled echo and hidden cursor. > > Looking at how other languages tackle this: > > * Rust (termion and crossterm): Rust relies on RAII guards where entering raw mode returns a > handle whose destructor automatically restores canonical cooked mode on drop or panic. > * Go (golang.org/x/term): Provides low-level primitives in the extended standard library > (MakeRaw, Restore, GetSize, ReadPassword) on top of which tools like Bubbletea are built. > * Node.js: Integrates raw mode toggling and size queries directly onto TTY streams via libuv. > * Python: Provides termios on POSIX and msvcrt on Windows in the standard library to guarantee > cross-platform terminal parity. > > Following your guidance, version 0.8.0 adopts the following design: > > 1. Namespace grouping: > All symbols are placed under the Io\Terminal namespace, avoiding top-level name reservation and > aligning with modern asynchronous and stream polling conventions. > > 2. Instance-based Terminal handle: > Classes are no longer static wrappers. The Io\Terminal\Terminal class encapsulates a stream > descriptor, created via named constructors stdin(), stdout(), stderr(), or by wrapping custom stream > resources. > > 3. Automatic RAII cleanup: > Both Terminal instances and ModeToken objects track active raw mode and automatically restore > terminal state upon destruction. If an uncaught exception terminates script execution, the > destructor restores canonical mode so the developer shell is never left broken. > > 4. Unbacked enums: > Backend, Stream, ColorDepth, and Key are now unbacked enums matching core standards. Methods > such as bits() on ColorDepth supply numerical details without scalar backing. > > 5. Free-standing procedural functions: > Io\Terminal provides procedural functions like is_tty(), read_key(), and get_size() for > functional script usage. > > 6. Compatibility: > The legacy Terminal facade and class aliases remain in place so existing userland code > continues to work smoothly. > > The complete codebase, 49 tests, and the continuous integration matrix covering Unix and > Windows across PHP versions 8.1 through 8.5 are live on GitHub and installable via PIE (package > prateekbhujel/php-terminal). > > The GitHub repository is here: > https://github.com/prateekbhujel/php-terminal > > Release v0.8.0 with prebuilt Windows DLL assets: > https://github.com/prateekbhujel/php-terminal/releases/tag/v0.8.0Ì¥÷^f´˜F > #ÿ�nµÁ > > I would love to hear any further thoughts on whether this design aligns with what you would > like to see for an RFC targeted at PHP 8.7. > > Thanks, > Pratik Meta question: can you please use your email’s “replyâ€� feature instead of writing a new email with the same subject each time. That allows people to follow the thread. — Rob

« previous php.internals (#132531) next »