Неблокирование на STDIN в PHP CLI

В любом случае, читать с STDIN с PHP, который не блокирует:

Я пробовал это:

stream_set_blocking(STDIN, false);
echo fread(STDIN, 1);

и это:

$stdin = fopen('php://stdin', 'r');
stream_set_blocking($stdin, false);
echo 'Press enter to force run command...' . PHP_EOL;
echo fread($stdin, 1);

но он по-прежнему блокируется до тех пор, пока fread не получит некоторые данные.

Я заметил несколько открытых отчетов об ошибках (7 лет), поэтому, если это невозможно сделать, знает ли кто-нибудь какие-нибудь сырые хаки, которые могут это сделать (в Windows и Linux)?

Ответы

Ответ 1

Вот что я мог придумать. Он отлично работает в Linux, но в Windows, как только я нажимаю клавишу, вход буферизуется до нажатия клавиши ввода. В настоящее время я пытаюсь найти способ отключить буферизацию в потоке или, в частности, STDIN в PHP.

<?php

function non_block_read($fd, &$data) {
    $read = array($fd);
    $write = array();
    $except = array();
    $result = stream_select($read, $write, $except, 0);
    if($result === false) throw new Exception('stream_select failed');
    if($result === 0) return false;
    $data = stream_get_line($fd, 1);
    return true;
}

while(1) {
    $x = "";
    if(non_block_read(STDIN, $x)) {
        echo "Input: " . $x . "\n";
        // handle your input here
    } else {
        echo ".";
        // perform your processing here
    }
}

?>

Ответ 2

Просто заметьте, что не блокирующий STDIN работает, сейчас.

Ответ 3

Петах, я не могу помочь с этой частью PHP напрямую, но я могу отнести вас к статье, которую я провел некоторое время назад, когда кто-то эмулировал транзисторы путем тестирования внутри оболочки script для существования ожидающих данные для именованного канала. Это захватывающее прочтение, и он делает shell-скрипты совершенно новым уровнем geekiness.: -)

Статья находится здесь: http://www.linusakesson.net/programming/pipelogic/

Итак... в ответ на ваш запрос "грубые хаки", я полагаю, вы могли бы шунтировать свой stdio через именованные каналы, затем exec() инструмент, источник которого включен по указанному выше URL, чтобы проверить, ожидает ли что-либо отправляется через трубу. Возможно, вам захочется разработать некоторые функции-обертки, которые помогут вам в работе.

Я подозреваю, что конвейерное решение Linux-only или, по крайней мере, потребует унифицированной операционной системы. Не знаю, как это можно сделать в Windows.

Ответ 4

system('stty cbreak');
while(true){
    if($char = fread(STDIN, 1)) {
        echo chr(8) . mb_strtoupper($char);
    }
}