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

===============

关注公众号:【硬核项目经理】获取最新文章

添加微信/QQ好友:【xiaoyuezigonggong/149844827】免费得PHP、项目管理学习资料

知乎、公众号、抖音、头条搜索【硬核项目经理】

B站ID:482780532

PHP的命令行扩展Readline相关函数学习的更多相关文章

  1. Linux命令行扩展和被括起来的集合

    命令行扩展:`` 和 $() 单引号'' 双引号"" 反向单引号`` 在很多场景下效果不同 [root@centos8 ~]#echo "echo $HOSTNAME&q ...

  2. Linux上超酷的命令行扩展工具Oh My Zsh

    Oh My Zsh 是一款社区驱动的命令行工具,正如它的主页上说的,Oh My Zsh 是一种生活方式.它基于 zsh 命令行,提供了主题配置,插件机制,已经内置的便捷操作.给我们一种全新的方式使用命 ...

  3. Linux命令行及Vim简单学习记录

    Linux命令行 1.打开命令行 Ctrl+Alt+t 2.目录 显示当前目录的文件列表 ls 跳转至当前目录中的x文件夹 cd x 返回根目录 cd 3.文件 新建文件1.cpp touch ./1 ...

  4. 探索Windows命令行系列(2):命令行工具入门

    1.理论基础 1.1.命令行的前世今生 1.2.命令执行规则 1.3.使用命令历史 2.使用入门 2.1.启动和关闭命令行 2.2.执行简单的命令 2.3.命令行执行程序使用技巧 3.总结 1.理论基 ...

  5. Windows命令行command的Shell命令详细解析和语法

    CMD命令大全及详细解释和语法 Microsoft Windows XP [版本 5.1.2600] 有关某个命令的详细信息,请键入 HELP 命令名 ASSOC    显示或修改文件扩展名关联. A ...

  6. ubuntu命令行下java工程编辑与算法(第四版)环境配置

    ubuntu命令行下java工程编辑与算法(第四版)环境配置 java 命令行 javac java 在学习算法(第四版)中的实例时,因需要安装配套的java编译环境,可是在编译java文件的时候总是 ...

  7. [Nuget]Nuget命令行工具安装

    下载 地址:https://www.nuget.org/downloads 直接下最新推荐版本(recommended latest)就好了. 是个单一的nuget.exe文件. 安装配置 想要在wi ...

  8. 转载:linux编程,命令行参数输入getopt

    下面资料来自百度百科: getopt(分析命令行参数) 相关函数 表头文件 #include<unistd.h> 定义函数 int getopt(int argc,char * const ...

  9. 学习 Linux,101: Linux 命令行

    概述 本教程将简要介绍 bash shell 的一些主要特性,涵盖以下主题: 使用命令行与 shell 和命令交互 使用有效的命令和命令序列 定义.修改.引用和导出环境变量 访问命令历史和编辑工具 调 ...

随机推荐

  1. MySQL慢查询及开启慢查询

    一.简介 开启慢查询日志,可以让MySQL记录下查询超过指定时间的语句,通过定位分析性能的瓶颈,才能更好的优化数据库系统的性能. 二.参数说明 slow_query_log 慢查询开启状态 slow_ ...

  2. html 去除重复边框

    <!DOCTYPE html><html> <head> <meta charset="utf-8"> <title>& ...

  3. Android 9.0 BufferSlot注解

    源码位置 /frameworks/native/libs/gui/include/gui/BufferSlot.h 源码 struct BufferSlot { BufferSlot() : mGra ...

  4. 【笔记】使用PCA对数据进行降噪(理解)

    使用PCA对数据进行降噪(使用手写数字实例) (在notebook中) 加载库并制作虚拟的数据并进行绘制 import numpy as np import matplotlib.pyplot as ...

  5. WPF/Winform 图表库LiveCharts

    早前的博客,自己动手写了几个图表饼状图,柱形图,折线图等,重在思路. 那么如果你不想这么麻烦自己动手,有没有现成的图表库那? 当然有,虽然我也刚开始用没多久,不过还是对这么良心的项目充满了敬佩!! g ...

  6. 玩转Spring生命周期之Lifecycle

    Lifecycle callbacks Initialization callbacks.Destruction callbacks要与容器的bean生命周期管理交互,即容器在启动后和容器在销毁前对每 ...

  7. sizeof()和 strlen()的区别 --- 个人笔记

    在学习C语言和linux的时候,遇到了一些常见问题.题目,有些很简单,有些容易出错,本人水平有限,未免会出错,今天有时间,就将以前做的笔记,一一拿出来,写写blog. sizeof()和 strlen ...

  8. CentOS7中apache的部署与配置

    一.apache的部署 输入命令 yum list | grep httpd 查看可安装的软件包,选择"httpd.x86_64"安装. 输入命令 yum install http ...

  9. Jmeter HTML 报告、Jenkins 配置

    目录 Jmeter 生成 HTML 测试报告 Jenkins 配置 Jmeter 生成 HTML 测试报告 JMeter 支持生成 HTML 测试报告, 以便从测试计划中获得图表和统计信息. 以上定义 ...

  10. Install Percona XtraDb Cluster 5.6.20 on CentOS 6.5

    http://blog.51cto.com/hj192837/1546149 You should have odd number of real nodes. node #1hostname: pe ...