Description
Originally, #18 aimed to look into ways to bring native non-blocking I/O to Windows - which still doesn't look like it's going to be supported any time soon unfortunately.
As an alternative, we may use a child process or thread to start blocking read operations on the STDIN stream without blocking the main process.
Here's the gist of this concept:
<?php
use React\Stream\ReadableResourceStream;
use React\EventLoop\Factory;
require __DIR__ . '/../vendor/autoload.php';
$fds = array(
0 => STDIN,
1 => array('pipe', 'w'),
2 => STDERR,
);
$p = proc_open('php ' . escapeshellarg(__DIR__ . '/stdin-child.php'), $fds, $pipes);
$loop = Factory::create();
$stdin = new ReadableResourceStream($pipes[1], $loop);
$stdin->on('data', function ($data) {
echo "\r";
var_dump($data);
});
$loop->run();
A simple child process could look something like this:
<?php
while (true) {
$data = fread(STDIN, 8192);
if ($data === '' || $data === false) {
return;
}
echo $data;
}
On top of this, we can't really access the STDOUT stream without blocking either, so we may have to use socket I/O instead (see e.g. clue/reactphp-sqlite#13).
On other platforms, we should also avoid inheriting active FDs to the child process (see e.g. clue/reactphp-sqlite#7).
We should be able to use pthreads, libeio or libuv to avoid spawning a child process and use a worker thread instead. This does however require a custom PHP extension to be present.
On top of this, the console will echo each keypress to the output immediately. We may have to disable console echo, but to the best of my knowledge this isn't possible from within PHP either. We may spawn a special binary though, e.g. https://github.com/Seldaek/hidden-input as the C/C++ implementation is relatively straight forward. As an ugly workaround may be able to overwrite the console output using a periodic timer like this:
$overwrite = $loop->addPeriodicTimer(0.005, function () {
echo "\r" . str_repeat(' ', 40) . "\r";
});
$stdin->on('close', function () use ($overwrite, $loop) {
$loop->cancelTimer($overwrite);
});
Sounds like fun? 🎉