[Discussion] Native terminal helpers for PHP CLI

php.internals

Pratik Bhujel

100 days ago
Hi internals, I have been experimenting with a small PHP extension for native terminal helpers: https://github.com/prateekbhujel/php-terminal The goal is to expose a small cross-platform CLI terminal layer for the pieces that are currently awkward to normalize in userland, especially on Windows: - checking whether stdin/stdout/stderr are TTYs - reading terminal size - enabling/restoring raw mode safely - reading a single key with normalized names - writing directly to stdout/stderr This started from a practical issue with prompt-style PHP CLIs. Laravel Prompts, for example, currently cannot use its normal interactive prompt flow on Windows because the backend depends on Unix-style terminal behavior. I opened a proof-of-concept integration here: https://github.com/laravel/prompts/pull/242 The extension is still alpha, and I am not proposing it for core right now. I mainly want feedback on whether this API shape makes sense from a PHP CLI/runtime point of view, and whether this is better kept as PECL/ecosystem work first. Initial release with Windows builds: https://github.com/prateekbhujel/php-terminal/releases/tag/v0.1.0 If this would be better discussed on internals-win first, I am happy to move it there. I am mainly looking for feedback on API shape, naming, Windows behavior, and missing primitives before taking it further. Thanks, Pratik

Derick Rethans

91 days ago
On Sun, 24 May 2026, Pratik Bhujel wrote:
> The goal is to expose a small cross-platform CLI terminal layer for > the pieces that are currently awkward to normalize in userland, > especially on Windows: > > - checking whether stdin/stdout/stderr are TTYs > - reading terminal size > - enabling/restoring raw mode safely > - reading a single key with normalized names > - writing directly to stdout/stderr
I think that this is something useful to have.
> The extension is still alpha, and I am not proposing it for core right > now. I mainly want feedback on whether this API shape makes sense from > a PHP CLI/runtime point of view, and whether this is better kept as > PECL/ecosystem work first.
I have had a look at the API, and from my point of view, I think I would like to see, with in mind a possible introduction into PHP core: - All functions to be part of a Terminal\Terminal class — we have guidelines for this in place: https://github.com/php/policies/blob/main/coding-standards-and-naming.rst#bundled-extensions - The getBackend() method should return an enum, as there are (currently) only two possible values: windows, and posix. - Reading a key returns either a string containing a character, or a sequence of characters describing an action (up, down, etc). I think, because both of these are strings, this is awkward. Perhaps it would be better for actual characters to return strings, and again, the special key-presses to be case of an Enum. In addition, would it return Unicode graphemes (think emojis), or just code points? - The stream names (STDOUT, STDIN, and STDERR) again should probably an Enum. cheers, Derick
-- https://derickrethans.nl | https://xdebug.org | https://xdebug.cloud Author of Xdebug. Like it? Consider supporting me: https://xdebug.org/support mastodon: @derickr@phpc.social @xdebug@phpc.social

Pratik Bhujel

91 days ago
Hi Derick, Thanks, that makes sense. I moved the package in that direction now. The current v0.3.0 API uses `Terminal\Terminal` with camelCase methods, plus `Terminal\Backend`, `Terminal\Stream`, and `Terminal\Key` enums: https://github.com/prateekbhujel/php-terminal/releases/tag/v0.3.0 I also removed the old procedural API instead of keeping compatibility around it. Since this is still pre-1.0 and not something people should be depending on yet, it felt better to make the shape cleaner now. For `readKey()`, special keys now return `Terminal\Key` cases, while printable input still returns a string. For Unicode, it currently returns the next encoded code point from the terminal, not a full grapheme cluster. That seemed like the clearer low-level primitive to me, but I am happy to adjust that if core would prefer a different contract. Thanks again for looking at it. Pratik Bhujel On Tue, Jun 2, 2026 at 2:27 PM Derick Rethans <derick@php.net> wrote:

Pratik Bhujel

87 days ago
Hi Derick, hi internals, Small update from my side: I pushed this further based on the feedback here. The current release is v0.4.1 now: https://github.com/prateekbhujel/php-terminal/releases/tag/v0.4.1 The API is now fully on the Terminal\Terminal class + enums shape. Raw mode restore uses an opaque Terminal\ModeToken object, special keys return Terminal\Key cases, printable input returns strings, and resize is surfaced as Terminal\Key::Resize on both POSIX and Windows. I also documented the current key scope more clearly: code points rather than grapheme clusters for now, no F1-F12/modifier normalization yet, and the POSIX sequence timeout defaults to 25ms. At this point I am mainly wondering what the right next step is: keep hardening it as a PECL/ecosystem package first, or is there anything in the current API shape that would already be a blocker if this ever moved closer to core? Thanks, Pratik On Tue, Jun 2, 2026 at 3:42 PM Pratik Bhujel <prateekbhujelpb@gmail.com> wrote: