关于php:PHP的命令行扩展Readline相关函数学习

40次阅读

共计 5136 个字符,预计需要花费 13 分钟才能阅读完成。

PHP 作为一个 Web 开发语言,相对来说,命令行程序并不是它的主战场。所以很多年老的 PHP 开发者可能连命令行脚本都没有写过,更别提交互式的命令操作了。而明天,咱们带来的这个扩大就是针对 PHP 的交互式命令行操作的。

readline 扩大函数实现了拜访 GNU Readline 库的接口。这些函数提供了可编辑的命令行。一个例子是在 Bash 中容许你应用箭头按键来插入字符或者翻看历史命令。因为这个库的交互个性,这个性能在你写的 Web 程序中没多大用处,然而当你写的脚本被用在命令行中时十分有用。

Readline 扩大的装置

Readline 扩大曾经退出了 PHP 的官网安装包中,如果是新的 PHP 环境,那么在编译的时候加上 –with-readline 即可。另外,咱们还须要装置操作系统的 Readline 库。当然,如果曾经是失常运行的 PHP,也能够从新编译一下。

# yum install -y readline-devel
# ./congiure xxxx --with-readline

默认状况下,如果没有在编译时减少 –whit-readline,Readline 的一些函数也是能够应用的,不过它们调用的是零碎的 libedit 库。有一些函数,比方 readline_list_history() 这种函数是无奈应用的。要想残缺的应用 Readline 扩大的能力,那么还是须要装置操作系统的 libreadline 库(下面 yum 装置的那个 readline-devel)并在 PHP 中进行相应参数的编译装置。

根本函数操作

Readline 扩大提供的函数不多,也十分的简略易用。

读取一行

$line = readline("请输出命令:"); // 读取命令行交互信息
echo $line, PHP_EOL; // aaa

运行 PHP 代码后,咱们就进入了命令提示符期待状态,并且会提醒“请输出命令:”,当咱们输出了 aaa 并回车之后,输出的内容就保留到了 $line 变量中。

命令历史列表相干操作

Readline 很弱小的一个性能就是它自带一套命令历史记录的性能。不过这个须要咱们本人手动地将命令退出到命令历史中。

$line = readline("请输出命令:"); // 读取命令行交互信息
if (!empty($line)) {readline_add_history($line); // 须要手动退出到命令历史记录中
}
echo $line, PHP_EOL; // aaa

$line = readline("请输出命令:");
if (!empty($line)) {readline_add_history($line);
}

// 命令历史记录列表
print_r(readline_list_history());
// Array
// (//     [0] => aaa
//     [1] => bbb
// )

应用 readline_add_history() 函数,就能够将一条命令退出到命令历史记录中,而后应用 readline_list_history() 就可能打印出咱们之前在交互式环境中发送过的命令记录。当然,如果只是这样简略的保留再打印那就没意思了,它还能将这些历史信息保留到内部文件进行存储。

// 将命令历史记录写入到一个文件中
readline_write_history('./readline_history');
// ./readline_history 中
// _HiStOrY_V2_
// aaa
// bbb

// 清理命令历史记录
readline_clear_history();
print_r(readline_list_history());
// Array
// (//)

// 从文件中读取命令历史记录
readline_read_history('./readline_history');
print_r(readline_list_history());
// Array
// (//     [0] => bbb
//     [1] => bbb
// )

咱们应用 readline_write_history() 函数将以后的命令历史记录保留到一个文件中,而后应用 readline_clear_history() 清理掉目前命令历史记录列表中的内容,这个时候打印 readline_list_history() 的话外面曾经没有任何货色了。接着,咱们再应用 readline_read_history() 将命令的历史记录从文件中加载回来进行还原。这一套性能是不是就十分有意思了,咱们能够记录客户的所有命令操作,不论是平安审查还是事件回放,都十分有用。

查看 Readline 状态

// 以后命令行外部的变量信息
print_r(readline_info());
// Array
// (//     [line_buffer] => bbb
//     [point] => 3
//     [end] => 3
//     [mark] => 0
//     [done] => 1
//     [pending_input] => 0
//     [prompt] => 请输出命令://     [terminal_name] => xterm-256color
//     [completion_append_character] =>
//     [completion_suppress_append] =>
//     [library_version] => 7.0
//     [readline_name] => other
//     [attempted_completion_over] => 0
// )

readline_info() 函数就比较简单了,咱们能够看到最初一条交互式命令的信息,外面包含了命令输出的内容 line_buffer,内容长度 point,提示信息 prompt 等内容。

命令提醒成果

在 Linux 等操作系统上,咱们想不起一个命令的全拼没关系,只须要记住它的前几个字符而后按两个 Tab 键就能够失去相干的命令提醒了。Readline 扩大库当然也为咱们筹备了这样的性能。

// 相似于命令行中按 Tab 键的提醒成果
readline_completion_function(function ($input, $index) {$commands = ['next', 'exit', 'quit'];
    $matches = [];
    if ($input) {
        // 如果关键字蕴含在命令中,提醒命令信息
        foreach ($commands as $c) {if (strpos($c, $input) !== false) {$matches[] = $c;
            }
        }
    }else{$matches = $commands;}
    return $matches;
});

// 应用 Tab 键测试一下吧
$line = trim(readline("请输出命令:"));
if (!empty($line)) {readline_add_history($line);
}
echo $line, PHP_EOL; // 以后输出的命令信息
// 如果命令是 exit 或者 quit,就退出程序执行
if($line == 'exit' || $line == 'quit'){exit;}

readline_completion_function() 函数会接管一个回调函数,当在交互式命令行模式下,也就是 readline 函数调用时,按下 Tab 键的时候,就会进入到这个函数的回调函数中。\$input 是以后曾经输出内容的值,$index 是第几个字符。咱们在这个回调函数中定义了几个默认的命令,当你键入一个 n 时间接按 Tab 键,程序就是提醒出残缺的 next 命令进去。当然,多个雷同的字母结尾的都是能够通过这个 $matches 数组返回出现的。

此外,在这段代码中,如果咱们输出了 exit 或者 quit。将退出程序的运行。

字符回调操作相干示例

最初几个函数咱们将通过一个简单的小测试来学习。

// 输入的内容进入这个回调函数中
function rl_callback($ret)
{
    global $c, $prompting;

    echo "您输出的内容是: $ret\n";
    $c++;

    readline_add_history($ret);

    // 限度了就调用 10 次,也能够通过命令行输出的内容来判断,比方下面的 exit 那种进行退出
    if ($c > 10) {
        $prompting = false;
        // 移除上一个装置的回调函数句柄并且复原终端设置
        readline_callback_handler_remove();} else {
        // 持续进行递归回调
        readline_callback_handler_install("[$c] 输出点什么内容:", 'rl_callback');

    }
}

$c = 1;
$prompting = true;

// 初始化一个 readline 回调接口,而后终端输入提示信息并立刻返回,须要期待 readline_callback_read_char() 函数调用后才会进入到回调函数中
readline_callback_handler_install("[$c] 输出点什么内容:", 'rl_callback');

// 当 $prompting 为 ture 时,始终期待输出信息
while ($prompting) {
    $w = null;
    $e = null;
    $r = array(STDIN);
    $n = stream_select($r, $w, $e, null);
    if ($n && in_array(STDIN, $r)) {
        // 当一个行被接管时读取一个字符并且告诉 readline 调用回调函数
        readline_callback_read_char();}
}

echo "完结,实现所有输出!\n";
// [1] 输出点什么内容: A
// 您输出的内容是: A
// [2] 输出点什么内容: B
// 您输出的内容是: B
// [3] 输出点什么内容: C
// 您输出的内容是: C
// [4] 输出点什么内容: D
// 您输出的内容是: D
// [5] 输出点什么内容: E
// 您输出的内容是: E
// [6] 输出点什么内容: F
// 您输出的内容是: F
// [7] 输出点什么内容: G
// 您输出的内容是: G
// [8] 输出点什么内容: H
// 您输出的内容是: H
// [9] 输出点什么内容: I
// 您输出的内容是: I
// [10] 输出点什么内容: J
// 您输出的内容是: J
// 完结,实现所有输出!print_r(readline_list_history());
// Array
// (//     [0] => A
//     [1] => B
//     [2] => C
//     [3] => D
//     [4] => E
//     [5] => F
//     [6] => G
//     [7] => H
//     [8] => I
//     [9] => J
// )

首先,咱们先不论下面的这个自定义的函数,间接向下看到 readline_callback_read_char()。它的作用是当一个行被接管时读取一个字符并且告诉 readline 调用回调函数。也就是当一行输出实现后,键入了回车之后,这个函数将告诉 Readline 组件去调用 readline_callback_handler_install() 注册的回调函数。

readline_callback_handler_install() 函数的性能是初始化一个 readline 回调接口,而后终端输入提示信息并立刻返回,如果在回调函数中不进行什么操作的话,这个函数就只是输入一个提醒就完结了。在咱们例子中的这个回调函数 rl_callback() 中,咱们依据以后接管命令的次数,判断如果接管的命令在十次内,则持续接管命令直到十次命令为止就调用 readline_callback_handler_remove() 移除上一个 readline_callback_handler_install() 装置的回调并复原终端的默认设置。

最初执行的后果就是正文中的内容,大家也能够本人复制下代码后运行调试,只有本人进行过的调试能力了解的更加深刻。

总结

Readline 很弱小,而且也是 PHP 默认安装包中自带的扩大。个别被退出默认的扩大都是通过工夫测验而且十分有用的扩大,大家能够依据这些内容再进行更加深刻的学习并使用到实战中。

测试代码:

https://github.com/zhangyue0503/dev-blog/blob/master/php/202006/source/PHP%E7%9A%84%E5%91%BD%E4%BB%A4%E8%A1%8C%E6%89%A9%E5%B1%95Readline%E7%9B%B8%E5%85%B3%E5%87%BD%E6%95%B0%E5%AD%A6%E4%B9%A0.php

参考文档:

https://www.php.net/manual/zh/book.readline.php
https://www.php.cn/php-weizijiaocheng-339883.html

===========

各自媒体平台均可搜寻【硬核项目经理】

正文完
 0