Hi
On 2026-09-27 19:19, Pratik Bhujel wrote:
I would like to formally propose the Io\Terminal API for PHP 8.7:
https://wiki.php.net/rfc/io_terminal
Pulling my reply to the top-level to reduce thread nesting. My apologies
for only getting back to the RFC now, the last few weeks have been busy.
I have just given the RFC another full read and have some more comments,
particularly around the “mode lease handling”, which is the by far most
complicated part of the RFC and where I feel that some extra explanation
and examples could help folks understand the behavior better than the
(extremely information dense) prose that the RFC currently contains.
Specifically:
(1) My understanding is that dropping the `ModeToken` is equivalent to
passing it to `restoreMode()`. I think it would make sense to make this
“destruction behavior” explicit by adding a `ModeToken::__destruct()`
function to the stub, even if the internal implementation does not
actually implement `__destruct()`. Seeing the `__destruct()` in the stub
is a good visual indicator that the class has “special behavior” on
destruction that goes beyond the usual “all associated resources are
freed or closed”. The restoration is not just freeing or closing, it's
actual behavior.
(2) An explicit example where multiple `ModeToken` leases are obtained
with explicit comments what happens at each step would go great lengths
of making the behavior approachable. From my understanding this would be
a correct example?
<?php
$terminal = Terminal::fromStdio();
$lease1 = $terminal->enableRawMode(); // Terminal is in raw mode
now.
$lease2 = $terminal->enableRawMode(); // No change to the terminal
mode. 2 leases active.
$lease3 = $terminal->enableRawMode(); // No change to the terminal
mode. 3 leases active.
assert($lease1 !== $lease2); // The lease objects are separate,
there is no singleton cache.
// Leases can be released in any order.
unset($lease2); // No change to the terminal mode. 2 leases active.
$terminal->restoreMode($lease1); // No change to the terminal mode.
1 lease active.
$terminal->restoreMode($lease3); // Terminal goes back to normal.
(void)$terminal->enableRawMode(); // Terminal is in raw mode and
immediately goes back to normal, because the returned token is
immediately destroyed.
and
<?php
$terminal = Terminal::fromStdio();
$lease1 = $terminal->enableRawMode(); // Terminal is in raw mode
now.
unset($terminal); // Terminal object is destroyed, but the actual
terminal remains in raw mode.
$terminal = Terminal::fromStdio(); // This Terminal object starts
off in raw mode!
unset($lease1); // The terminal goes back to normal.
Perhaps there are more interactions that would be worth showing as an
example.
(3) Given the `(void)$terminal->enableRawMode()` call in the first
example, I believe that `Terminal::enableRawMode()` should be
`#[\NoDiscard]`.
(4) The RFC mentions “Final restoration restores the saved snapshot,
rather than merging changes made externally while leases were active.”.
It should be clear what is being restored. Is it just the terminal mode
(raw or not)? What happens if the terminal was already in raw mode (e.g.
using a `stty` call) when `enableRawMode()` is called? Will
`enableRawMode()` be a no-op and will returning the lease put the
terminal back into raw mode when another `stty` call already put it in
normal mode? Or will it return a no-op lease?
(5) In the “Reading keys” section, the RFC says “The sequence wait
cannot extend the overall timeout.”. Will this be a ValueError, or will
it silently be clamped?
(6) For reading lines: I think the removal of the line terminator is
inconsistent with every existing API. I don't necessarily disagree with
the proposed behavior, but the RFC should properly justify the
difference. This is also important for the documentation.
(7) The “Input state and sequential reads” section could also do with
examples.
(8) I'm not sure if `Key::Resize` is good design. Just to throw a
suggestion in the ring: We could have two enums `Key` and `Metadata` (or
similar), with `readKey()` returning `Key|Metadata`. No strong opinion
on that, though.
----------
Overall I'm pretty happy with the proposed API now. My main concern is
the lack of examples which make the RFC very hard to approach and
probably makes it hard for voters to make an educated decisions.
Best regards
Tim Düsterhus