Readline add history: примеры (PHP)

Использование readline_add_history для управления историей ввода
Раздел: Ввод данных
readline_add_history(string $prompt): bool
Функция readline_add_history

Функция readline_add_history является частью модуля Readline в PHP. Она используется для добавления строки в историю ввода. История сохраняется между вызовами скрипта в рамках одной сессии интерпретатора, если используется встроенный CLI-сервер или интерактивный режим.

Эта функция применяется в интерактивных командных строковых (CLI) приложениях на PHP для запоминания ранее введённых команд или данных, что позволяет пользователю перемещаться по ним с помощью клавиш со стрелками вверх и вниз.

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

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

  • string $line - Строка, которую необходимо добавить в историю. Строка должна заканчиваться на новой строке, как правило, это пользовательский ввод, полученный через readline().

Функция возвращает true в случае успешного выполнения.

Краткие примеры использования
Пример 1: Базовое добавление в историю
<?php
// Включаем поддержку readline, если не включена автоматически
if (!function_exists('readline')) {
    dl('readline.so'); // Для Unix-систем, может потребоваться
}

$command = readline('Введите команду: ');
readline_add_history($command);
echo 'Команда добавлена в историю.';
?>
Введите команду: echo 'Hello'
Команда добавлена в историю.
Пример 2: Добавление нескольких строк
<?php
$inputs = [];
for ($i = 0; $i < 3; $i++) {
    $input = readline('Элемент ' . ($i+1) . ': ');
    $inputs[] = $input;
    readline_add_history($input);
}
echo 'Введённые данные: ' . implode(', ', $inputs);
?>
Элемент 1: Apple
Элемент 2: Banana
Элемент 3: Cherry
Введённые данные: Apple, Banana, Cherry
Похожие функции в PHP

Прямых аналогов readline_add_history в стандартной библиотеке PHP нет, так как она специфична для модуля Readline. Однако для чтения ввода в CLI-среде можно использовать:

  • fgets(STDIN) - Читает строку из стандартного ввода. Не поддерживает историю, автодополнение или управляющие последовательности. Подходит для простейшего ввода.
  • stream_get_line(STDIN, length, "\n") - Более контролируемое чтение строки из потока.
  • Библиотеки вроде "php-school/cli-menu" - Предоставляют полноценные интерактивные меню с историей и другими функциями, но требуют установки.

readline_add_history предпочтительнее, когда нужна именно история ввода в нативном интерактивном CLI-приложении без сторонних зависимостей.

Типичные ошибки
Ошибка 1: Функция недоступна
<?php
// Если модуль readline не установлен или отключён
$line = 'test';
$result = @readline_add_history($line);
if (!$result && !function_exists('readline_add_history')) {
    echo 'Ошибка: Модуль readline не доступен.';
}
?>
Ошибка: Модуль readline не доступен.
Ошибка 2: Передача нестрокового аргумента
<?php
// PHP 8 выдаст TypeError
readline_add_history(12345);
?>
Fatal error: Uncaught TypeError: readline_add_history(): Argument #1 ($line) must be of type string, int given...
Ошибка 3: Использование вне CLI SAPI
<?php
// При запуске через веб-сервер (не CLI)
if (php_sapi_name() !== 'cli') {
    die('Эта функция работает только в CLI-режиме.');
}
readline_add_history('test');
?>
Эта функция работает только в CLI-режиме.
Изменения в версиях PHP

Для функции readline_add_history значительных изменений в поведении в последних основных версиях PHP (5.x, 7.x, 8.x) не зафиксировано. Основные относящиеся к модулю изменения:

  • PHP 8.0.0: Параметр $line теперь имеет явный тип string. Передача нестрокового значения вызывает TypeError. Ранее неявное преобразование типов могло приводить к неожиданным результатам.
  • PHP 5.1.0: Модуль Readline был обновлён для использования библиотеки libedit. Совместимость с GNU Readline сохраняется, но некоторые расширенные возможности могут отличаться.

Рекомендуется всегда проверять доступность модуля, особенно в кросс-платформенных проектах.

Расширенные примеры
Пример 1: Интерактивный цикл с сохранением истории и выходом по команде
Пример php
<?php
$historyFile = sys_get_temp_dir() . '/php_readline_history.txt';
// Загружаем историю из файла, если существует
if (file_exists($historyFile)) {
    readline_read_history($historyFile);
}

while (true) {
    $line = readline('> ');
    if ($line === 'exit') {
        break;
    }
    if (trim($line) !== '') {
        readline_add_history($line);
        echo 'Вы сказали: ' . $line . PHP_EOL;
    }
}
// Сохраняем историю в файл
readline_write_history($historyFile);
echo 'История сохранена. До свидания!' . PHP_EOL;
?>
> echo 1
Вы сказали: echo 1
> $a = 10
Вы сказали: $a = 10
> exit
История сохранена. До свидания!
Пример 2: Фильтрация перед добавлением в историю
Пример php
<?php
function addToHistoryIfValid($line) {
    // Не добавляем пустые строки или команды, начинающиеся с пробела
    if (trim($line) === '' || strpos($line, ' ') === 0) {
        return false;
    }
    return readline_add_history($line);
}

$input = readline('Введите команду (пробелы в начале игнорируются): ');
if (addToHistoryIfValid($input)) {
    echo 'Добавлено.';
} else {
    echo 'Не добавлено (фильтр).';
}
?>
Введите команду (пробелы в начале игнорируются):   secret
Не добавлено (фильтр).
Пример 3: Интеграция с автодополнением и чтением истории
Пример php
<?php
// Функция автодополнения
function autoComplete($partial, $index) {
    $commands = ['list', 'delete', 'update', 'exit', 'help'];
    return $commands[$index] ?? null;
}

readline_completion_function('autoComplete');

// Добавляем несколько команд в историю для демонстрации
readline_add_history('list');
readline_add_history('help');

$cmd = readline('Команда (попробуйте нажать Tab): ');
readline_add_history($cmd);
echo 'Выполняем: ' . $cmd . PHP_EOL;

// Показать всю текущую историю
$hist = readline_list_history();
echo 'Текущая история: ' . implode(', ', $hist);
?>
Команда (попробуйте нажать Tab): li<Tab> // Пользователь нажимает Tab
Команда (попробуйте нажать Tab): list // Автодополнение
Выполняем: list
Текущая история: list, help, list
Аналоги в других языках
Python: readline.add_history
import readline
command = input('Введите команду: ')
readline.add_history(command)
print(f'Добавлено: {command}')
Введите команду: import os
Добавлено: import os

В Python модуль readline предоставляет почти идентичный интерфейс. Он часто доступен по умолчанию в Unix-подобных системах.

JavaScript (Node.js): readline.createInterface и .history
const readline = require('readline');
const rl = readline.createInterface({
  input: process.stdin,
  output: process.stdout,
  historySize: 50
});
rl.question('Введите что-то: ', (answer) => {
  // История управляется автоматически интерфейсом
  console.log(`Вы ввели: ${answer}`);
  console.log('История:', rl.history);
  rl.close();
});
Введите что-то: console.log(1)
Вы ввели: console.log(1)
История: [ 'console.log(1)' ]

В Node.js история обычно управляется автоматически объектом интерфейса readline, но можно получить к ней доступ через свойство .history.

MySQL: Нет прямой аналогии

В MySQL нет встроенной истории ввода на уровне функций языка, так как это СУБД. История команд обычно предоставляется клиентским приложением (например, mysql cli, который использует GNU Readline или libedit).

PHP readline_add_history function comments

En
Readline add history Adds a line to the history