2024 年 PHP 日本大会

交互式 shell

如果 PHP 使用 --with-readline 选项编译,则 CLI SAPI 提供一个使用 -a 选项的交互式 shell。从 PHP 7.1.0 开始,如果启用了 readline 扩展,则 Windows 上也提供交互式 shell。

使用交互式 shell,您可以键入 PHP 代码并直接执行。

示例 #1 使用交互式 shell 执行代码

$ php -a
Interactive shell

php > echo 5+8;
13
php > function addTwo($n)
php > {
php { return $n + 2;
php { }
php > var_dump(addtwo(2));
int(4)
php >

交互式 shell 还具有针对函数、常量、类名、变量、静态方法调用和类常量的制表符补全功能。

示例 #2 制表符补全

当有多个可能的补全项时,按两次制表键将显示这些补全项的列表。

php > strp[TAB][TAB]
strpbrk   strpos    strptime  
php > strp

当只有一个可能的补全项时,按一次制表键将完成同一行上的其余部分。

php > strpt[TAB]ime(

补全也适用于在当前交互式 shell 会话期间定义的名称。

php > $fooThisIsAReallyLongVariableName = 42;
php > $foo[TAB]ThisIsAReallyLongVariableName

交互式 shell 存储您的历史记录,可以使用向上和向下键访问。历史记录保存在 ~/.php_history 文件中。

CLI SAPI 提供 php.ini 设置 cli.pagercli.promptcli.pager 设置允许外部程序(例如 less)充当输出的分页器,而不是直接显示在屏幕上。cli.prompt 设置可以更改 php > 提示符。

还可以使用简写符号在交互式 shell 中设置 php.ini 设置。

示例 #3 在交互式 shell 中设置 php.ini 设置

cli.prompt 设置

php > #cli.prompt=hello world :> 
hello world :>

使用反引号,可以在提示符中执行 PHP 代码。

php > #cli.prompt=`echo date('H:i:s');` php > 
15:49:35 php > echo 'hi';
hi
15:49:43 php > sleep(2);
15:49:45 php >

将分页器设置为 less

php > #cli.pager=less
php > phpinfo();
(output displayed in less)
php >

cli.prompt 设置支持一些转义序列。

cli.prompt 转义序列
序列 描述
\e 用于向提示符添加颜色。例如 \e[032m\v \e[031m\b \e[34m\> \e[0m
\v PHP 版本。
\b 指示 PHP 位于哪个块中。例如 /* 表示位于多行注释内。外部范围由 php 表示。
\> 指示提示符字符。默认情况下为 >,但在 shell 位于未终止的块或字符串内时会发生更改。可能的字符为:' " { ( >

注意:

通过 auto_prepend_fileauto_append_file 包含的文件在此模式下被解析,但有一些限制 - 例如,必须在调用函数之前定义函数。

交互模式

如果 readline 扩展不可用,在 PHP 8.1.0 之前,使用 -a 选项调用 CLI SAPI 提供交互模式。在此模式下,完整的 PHP 脚本应该通过 STDIN 提供,并在使用 CTRL +D (POSIX) 或 CTRL +Z 后跟+ENTER (Windows) 终止后,对该脚本进行评估。这基本上与不使用 -a 选项调用 CLI SAPI 相同。

从 PHP 8.1.0 开始,如果 readline 扩展不可用,则使用 -a 选项调用 CLI SAPI 将失败。

添加注释

用户贡献的注释 7 条注释

177
Ryan P
12 年前
交互式 Shell 和交互模式并不相同,尽管名称和功能相似。

如果您键入“php -a”并得到“交互式 Shell”响应,后跟“php>”提示符,则表示您具有交互式 shell(PHP 使用 readline 支持编译)。如果改为得到“已启用交互模式”的响应,则表示您没有交互式 shell,本文不适用于您。

您还可以检查“php -m”,查看 readline 是否列在输出中 - 如果没有,则表示您没有交互式 shell。

交互模式基本上就像使用 stdin 作为文件输入运行 php 一样。您只需键入代码,完成后(Ctrl-D),php 将执行您键入的任何内容,就像它是一个普通的 PHP (PHTML) 文件一样 - 因此您在交互模式下以“
交互式 shell 会在您完成表达式(使用;或})时评估每个表达式,在不终止执行的情况下报告错误,并通过 readline 支持标准 shell 功能(历史记录、制表符补全等)。它是交互模式的增强版本,只有在您拥有所需库的情况下才能使用,并且它是一个实际的 PHP shell,它将您键入的所有内容解释为 PHP 代码 - 使用“
最后,如果您在 Windows 上运行,您可能遇到问题。从我在此处看到的其他评论来看,您没有 readline,如果没有 readline,则没有交互式 shell。
60
spencer at aninternetpresence dot net
13 年前
在 Windows 中,在结束 PHP 标签后按 Enter,然后按 Ctrl-Z 表示文件结束。

C:\>php -a
已启用交互模式

<?php
echo "Hello, world!";
?>
^Z
Hello, world!

您可以在交互模式中使用向上和向下箭头来回忆您之前运行的代码。
14
#linuxmint-es
7 年前
要在 Debian/Ubuntu/Linux Mint 等 GNU/Linux 发行版上使用已启用的交互模式,您必须从官方存储库安装“php*-cli”和“php*-readline”包。
示例
>$sudo aptitude install php5-cli php5-readline

之后您可以使用交互模式。
示例
~ $ php -a
已启用交互模式

php >echo "hola mundo!\n";
hola mundo!
php >

我希望有人能帮到他!
14
匿名
14 年前
再补充几点…

1) 按回车键实际上意味着“执行此命令”。仍然需要分号来表示行尾。这意味着,执行以下操作将产生解析错误

php > print "test"
php > print "asdf";

而执行以下操作则没问题

php > print "test"
php > ."asdf";

2) 致命错误可能导致您退出 shell

name@local:~$ php -a
php > asdf();

致命错误:调用未定义函数……
name@local:~$

3) 用户自定义函数不会从一个 shell 会话保存到下一个 shell 会话的历史记录中。

4) 这应该很明显,但要退出 shell,只需在 php 提示符下键入“quit”。

5) 从某种意义上说,shell 交互可以被认为是线性地遵循一个常规 php 文件,只是它是实时和动态的。如果您定义了一个在当前 shell 中先前已定义的函数,则只有在输入该结束括号时才会收到致命的“函数已定义”错误。而且,虽然“包含”自定义函数工具集或一些脚本附加 php 文件相当方便,但如果您编辑这些文件并希望再次“重新包含”它,则会导致致命的“函数 x 已定义”错误。
2
John
6年前
如果您删除了您的“~/.php_history”,则**必须**手动重新创建该文件!

因为在我删除历史文件后,“php -a”(交互模式)不再保存任何历史记录了。

在我运行“touch ~/.php_history”创建空文件后,它才开始工作。从那时起,PHP 又开始保存历史记录了!

我认为这有点不寻常。通常,应用程序会自行重新创建其历史文件。但是请注意 PHP 的工作方式就是这样,各位!:-)
2
Gray
4年前
添加颜色时,请不要忘记 PHP 使用与 Bash 相同的“readline”,因此它同样需要将所有颜色代码包装在特殊的标记字符中。

如果您只是将原始颜色代码添加到提示符中,您会注意到长行不再正确换行——Readline 不再知道提示符的宽度。

要解决此问题,您需要以“0x01”字节(即 Ctrl-A,即 SOH)开头每个颜色代码,并以“0x02”字节(即 Ctrl-B,即 STX)结尾。这些没有转义符——您必须将控制字符直接放入您的 php-cli.ini 中。

例如

<?php

// cli.prompt = <SOH>\e[1m<STX> PHP! \> <SOH>\e[m<STX>

echo "cli.prompt = \x01\\e[1m\x02 PHP! \x01\\e[m\x02\n";
?>
1
turabgarip at gmail dot com
7个月前
请注意,使用任何方法退出交互式 shell 时,不会触发析构函数。(例如 CTRL + D、CTRL + Z 或 CTRL + C)。

由于交互式 shell 实际上是一个持续运行时,因此析构函数永远不会满足“脚本结束”条件。退出交互式 shell 不被认为是脚本结束,而是解释器进程的结束。由于进程已死;它无法运行析构函数。

因此,运行析构函数的唯一方法是删除对相应对象的全部引用。例如

<?php

class A {
public function
__destructor() {
// 结束 PHP 交互式 shell 会话后,这将永远不会运行。
}
}

$a = new A();

// 这是析构函数能够运行的唯一方法。
$a = null; // 或;
unset($a);

?>
To Top