Readline completion function: примеры (PHP)

Использование readline_completion_function для автодополнения в PHP
Раздел: Ввод данных
readline_completion_function(callable $callback): bool
Назначение и базовые параметры функции

Функция readline_completion_function в PHP регистрирует callback-функцию для автодополнения вводимых данных в интерактивной командной строке. Она используется исключительно в CLI-режиме для улучшения пользовательского интерфейса.

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

Функция принимает единственный аргумент:

  • $callback (callable) — Функция, возвращающая массив возможных вариантов дополнения для текущего ввода.

Callback-функция получает два параметра: текущий введенный текст и позицию курсора. Она должна возвращать массив строк-кандидатов для автодополнения.

Простые примеры использования
Базовое дополнение команд
<?php
function complete($input, $index) {
    $commands = ['start', 'stop', 'restart', 'status', 'exit'];
    return array_filter($commands, function($cmd) use ($input) {
        return str_starts_with($cmd, $input);
    });
}

readline_completion_function('complete');
$line = readline('Введите команду: ');
echo 'Вы ввели: ' . $line;
?>
> Введите команду: st
> (при нажатии Tab выведет варианты: start, stop, status)
> Вы ввели: start
Дополнение с учетом позиции курсора
<?php
function completePaths($input, $index) {
    // Игнорируем позицию курсора в этом примере
    $files = glob($input . '*');
    return $files ?: [];
}

readline_completion_function('completePaths');
$file = readline('Укажите файл: ');
?>
Укажите файл: ./app
(при нажатии Tab предложит файлы: ./app.log, ./app.php, ./application/)
Похожие функции в PHP

Для работы с интерактивным вводом в PHP существуют и другие инструменты:

  • readline() — Основная функция для чтения строки из консоли. Часто используется вместе с readline_completion_function.
  • readline_add_history() — Добавляет строку в историю ввода, что полезно для повторного использования команд.
  • readline_read_history() и readline_write_history() — Функции для сохранения и загрузки истории между сессиями.

Функция readline_completion_function уникальна в своем роде, так как предоставляет именно механизм автодополнения. Альтернативой может быть самостоятельная обработка ввода с помощью readline и последующий вывод подсказок, но это менее удобно.

Аналоги в других языках
Python: модуль readline
import readline

def completer(text, state):
    commands = ['start', 'stop', 'restart']
    options = [cmd for cmd in commands if cmd.startswith(text)]
    return options[state] if state < len(options) else None

readline.set_completer(completer)
readline.parse_and_bind('tab: complete')

user_input = input('Введите команду: ')
print(f'Вы ввели: {user_input}')
JavaScript (Node.js): пакет readline
const readline = require('readline');
const rl = readline.createInterface({
    input: process.stdin,
    output: process.stdout,
    completer: (line) => {
        const commands = ['start', 'stop', 'restart'];
        const hits = commands.filter(c => c.startsWith(line));
        return [hits, line];
    }
});

rl.question('Введите команду: ', (answer) => {
    console.log(`Вы ввели: ${answer}`);
    rl.close();
});

В отличие от PHP, где функция работает только в CLI, JavaScript-реализация через Node.js также ограничена серверной средой, но имеет схожий принцип работы через callback.

Распространенные ошибки
Использование вне CLI-режима
<?php
// Запуск в веб-сервере вызовет предупреждение
function completer($input, $index) { return []; }
readline_completion_function('completer');
?>
Warning: readline_completion_function(): This is not supported on Windows in ...
Callback возвращает не массив
<?php
readline_completion_function(function() {
    return 'string_instead_of_array'; // Ошибка
});
$input = readline('Test: ');
?>
// Автодополнение не будет работать, могут возникнуть непредсказуемые ошибки.
Попытка дополнения без зарегистрированной функции
<?php
// Не вызывали readline_completion_function
$input = readline('Ввод: '); // Нажатие Tab не даст эффекта
?>
История изменений функции

Функция readline completion function была добавлена в PHP 4.0.0. Существенных изменений в ее поведении в последних версиях PHP (7.x, 8.x) не было. Однако, начиная с PHP 8.0, усилена типизация, и callback-функция должна возвращать строго массив.

В PHP 8.1+ функция стабильна, но ее работа сильно зависит от установленной и скомпилированной библиотеки readline. На Windows поддержка может быть ограничена.

Расширенные примеры
Контекстное дополнение для мини-терминала
<?php
$context = 'user';

function advancedComplete($input, $index) {
    global $context;
    $map = [
        'user' => ['add', 'delete', 'list'],
        'file' => ['create', 'remove', 'open'],
        'system' => ['shutdown', 'reboot']
    ];
    $candidates = $map[$context] ?? [];
    return array_filter($candidates, fn($cmd) => str_starts_with($cmd, $input));
}

readline_completion_function('advancedComplete');

while (true) {
    $cmd = readline('> ');
    if ($cmd === 'switch user') $context = 'user';
    elseif ($cmd === 'switch file') $context = 'file';
    elseif ($cmd === 'exit') break;
    readline_add_history($cmd);
}
?>
Дополнение с подсказками из файла
<?php
function fileBasedComplete($input, $index) {
    if (!file_exists('dictionary.txt')) return [];
    $words = file('dictionary.txt', FILE_IGNORE_NEW_LINES);
    return preg_grep('/^' . preg_quote($input, '/') . '/', $words);
}

readline_completion_function('fileBasedComplete');
$word = readline('Введите слово: ');
?>
Многоуровневое автодополнение
<?php
function multiLevelComplete($input, $index) {
    $parts = explode(' ', $input);
    $lastPart = end($parts);
    
    if (count($parts) === 1) {
        $firstLevel = ['config ', 'show ', 'set '];
        return array_filter($firstLevel, fn($item) => str_starts_with($item, $lastPart));
    }
    
    if ($parts[0] === 'config') {
        $secondLevel = ['--user=', '--path=', '--verbose'];
        return array_filter($secondLevel, fn($item) => str_starts_with($item, $lastPart));
    }
    return [];
}

readline_completion_function('multiLevelComplete');
$command = readline('Введите команду: ');
?>

PHP readline_completion_function function comments

En
Readline completion function Registers a completion function