Re: Re: [PHP DEV] [Discussion] Native terminal helpers for PHP CLI
| From: | Rob Landers | 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