Readline callback handler install: примеры (PHP)

Асинхронный ввод в PHP через readline_callback_handler_install
Раздел: Ввод данных
readline_callback_handler_install(string $prompt, callable $callback): bool
Описание функции readline_callback_handler_install

Функция readline_callback_handler_install() инициализирует систему обработки ввода построчно с обратными вызовами. Она позволяет читать ввод из командной строки асинхронно, не блокируя выполнение скрипта, пока пользователь вводит данные. Эта функция полезна для создания интерактивных CLI-приложений, где необходимо выполнять фоновые задачи во время ожидания ввода.

Аргументы функции

Функция принимает два обязательных аргумента:

  • prompt (string) – Строка приглашения, которая отображается пользователю перед вводом.
  • callback (callable) – Функция обратного вызова, которая выполняется после завершения ввода строки. В эту функцию передается введенная строка.

Функция не возвращает значение. Она подготавливает систему обратных вызовов readline. Для ее работы необходим запуск readline_callback_read_char() в цикле.

Короткие примеры использования
Базовый пример с callback
<?php
function handleInput($input) {
    echo "Вы ввели: $input\n";
}

readline_callback_handler_install("Введите команду: ", 'handleInput');

while (true) {
    $w = null;
    $e = null;
    $r = array(STDIN);
    $n = stream_select($r, $w, $e, null);
    if ($n) {
        readline_callback_read_char();
    }
}
Введите команду: привет
Вы ввели: привет
Пример с анонимной функцией
<?php
readline_callback_handler_install("Ваше имя: ", function($answer) {
    echo "Здравствуйте, $answer!\n";
    readline_callback_handler_remove(); // Удаляем обработчик после ввода
});

while (true) {
    readline_callback_read_char(); // Ждем ввода
}
Ваше имя: Анна
Здравствуйте, Анна!
Похожие функции в PHP

В PHP для чтения ввода из командной строки существуют другие функции.

Функция readline() является синхронным аналогом. Она блокирует выполнение скрипта до получения ввода от пользователя.

$input = readline("Введите что-нибудь: ");
echo "Вы ввели: $input";
fgets(STDIN)

Функция fgets() со стандартным потоком ввода также читает строку синхронно.

echo "Введите текст: ";
$input = fgets(STDIN);
echo "Текст: $input";

readline_callback_handler_install() предпочтительнее использовать при создании интерактивных CLI-приложений с фоновыми задачами. Функции readline() и fgets() подходят для простых скриптов, где не требуется асинхронность.

Альтернативы в других языках
Python: input() и select

В Python аналогом синхронного чтения является функция input(). Для асинхронного ввода можно использовать модуль select с sys.stdin.

import sys
import select

def async_input(prompt):
    sys.stdout.write(prompt)
    sys.stdout.flush()
    ready, _, _ = select.select([sys.stdin], [], [], None)
    if ready:
        return sys.stdin.readline().rstrip('\n')
    return None

print("Введите имя:")
name = async_input("Имя: ")
print(f"Привет, {name}")
JavaScript (Node.js): readline module

В Node.js модуль readline предоставляет интерфейс для чтения потока ввода построчно.

const readline = require('readline');
const rl = readline.createInterface({
  input: process.stdin,
  output: process.stdout
});
rl.question('Ваш возраст: ', (answer) => {
  console.log(`Вам ${answer} лет`);
  rl.close();
});

Основное отличие PHP функции — необходимость ручного управления циклом событий через readline_callback_read_char(). В Node.js и Python с asyncio цикл событий управляется средой выполнения.

Типичные ошибки
Отсутствие цикла с readline_callback_read_char

Без вызова readline_callback_read_char() callback не будет выполнен.

<?php
readline_callback_handler_install("Тест: ", function($input) {
    echo "$input\n";
});
// Цикл отсутствует - ничего не произойдет
Тест: ввод
// Никакого вывода
Попытка использования вне CLI

Функция доступна только в CLI SAPI.

<?php
if (php_sapi_name() !== 'cli') {
    echo "Только для CLI\n";
    exit;
}
// Код функции
Не удаление обработчика

При повторной установке обработчика без удаления предыдущего может возникнуть ошибка.

<?php
readline_callback_handler_install("Первый: ", function($input) { echo "1"; });
readline_callback_handler_install("Второй: ", function($input) { echo "2"; }); // Предупреждение
Изменения в версиях PHP

Функция readline_callback_handler_install() была введена в PHP 5.1.0. Значительных изменений в ее работе в последних версиях PHP не было. Начиная с PHP 7.1.0, расширение readline по умолчанию встроено в CLI SAPI, что упрощает использование. В PHP 8.0 и 8.1 изменений в поведении этой конкретной функции не зафиксировано. Однако всегда рекомендуется проверять документацию на предмет изменений в обработке ошибок или незначительных улучшений.

Расширенные примеры
Интерактивное меню с фоновым таймером
<?php
$lastActivity = time();
readline_callback_handler_install("Меню (введите 'выход' для выхода): ", function($input) use (&$lastActivity) {
    $lastActivity = time();
    if (trim($input) === 'выход') {
        echo "Завершение работы.\n";
        readline_callback_handler_remove();
        exit;
    }
    echo "Вы выбрали: $input\n";
});

while (true) {
    $r = array(STDIN);
    $w = null;
    $e = null;
    $timeout = 5;
    $n = stream_select($r, $w, $e, $timeout);
    if ($n) {
        readline_callback_read_char();
    } else {
        $idle = time() - $lastActivity;
        if ($idle >= 10) {
            echo "\nНеактивность 10 секунд. Ожидание ввода...\n";
            $lastActivity = time();
        }
    }
}
Многопоточный ввод с обработкой сигналов
<?php
declare(ticks=1);
pcntl_signal(SIGINT, function() {
    echo "\nПолучен сигнал SIGINT. Завершение.\n";
    readline_callback_handler_remove();
    exit;
});

readline_callback_handler_install("Введите текст (Ctrl+C для выхода): ", function($input) {
    echo "Длина строки: " . strlen($input) . "\n";
});

while (true) {
    pcntl_signal_dispatch();
    $r = array(STDIN);
    $n = stream_select($r, $w, $e, 1);
    if ($n) {
        readline_callback_read_char();
    }
}
Чтение нескольких строк до ключевого слова
<?php
$lines = [];
readline_callback_handler_install("Введите строку (или 'стоп'): ", function($input) use (&$lines) {
    if (trim($input) === 'стоп') {
        echo "\nВсе строки:\n" . implode("\n", $lines);
        readline_callback_handler_remove();
        exit;
    }
    $lines[] = $input;
});

while (true) {
    readline_callback_read_char();
}

PHP readline_callback_handler_install function comments

En
Readline callback handler install Initializes the readline callback interface and terminal, prints the prompt and returns immediately