• 认真地记录技术中遇到的坑!
  • 能摸鱼真是太好啦!嘿嘿嘿!

PHP命令行CLI参数处理和交互

PHP 悠悠 5年前 (2019-03-25) 6639次浏览 0个评论

PHP的命令行模式

自从PHP4.3.0开始,PHP提供了CLI(Command Line Interface)命令行接口,CLI SAPI模块主要用于PHP外壳应用的开发。

区别于CGI(Common Gateway Interface),CLI有很多不同的特性:

  • 与 CGI SAPI 不同,CLI输出没有任何头信息
  • 在运行时,CLI不会把工作目录改为脚本的当前目录
  • 出错时CLI输出纯文本的错误信息(非 HTML 格式)
  • CLI SAPI 强制覆盖了 php.ini 中的某些设置,因为这些设置在命令行没有意义,下面设置在CLI强制覆盖
    • html_errors: false,取消HTML错误信息
    • implicit_flush: true,print和echo的输出会立即写到输出端,而不做任何缓冲,可使用output buffering实现输出缓冲
    • max_execution_time: 0,命令行运行的php脚本可能等待输入等,运行时间可能很长
    • register_argc_argv: true,总是可以在命令行模式下访问命令行参数
  • CLI可以独立于Web Server运行

PHP获取命令行参数的方法

访问全局变量$argv, $argc

在PHP的命令行模式下,可在脚本中直接访问$argv, $argc两个全局变量:

  • $argv: 命令行实际参数的数组
  • $argc: 命令行参数的个数

比如现在有一个arg_test.php的文件:

<?php
var_dump(argc);
var_dump(argv);

在命令行以下面的命令启动:php arg_test.php -t 800 a set,输出如下:

int(5)
array(5) {
  [0]=>
  string(12) "arg_test.php"
  [1]=>
  string(2) "-t"
  [2]=>
  string(3) "800"
  [3]=>
  string(1) "a"
  [4]=>
  string(4) "bset"
}

一个空格区分一个参数,包括当前的脚本名称,都会放在$argv中,当时这种方式不便于处理-t这样的参数,需要自己进行解析。

PHPgetopt参数处理函数

getopt函数是PHP自带专门用来处理复杂命令行参数的内置函数。原型如下:

getopt ( string options [, arraylongopts [, int &$optind ]] ) : array

关于getopt()的说明如下:

  • options: 该字符串中的每个字符会被当做选项字符,匹配以单个连字符(-)传入到脚本的选项,比如x识别-x选项,只允许a-z,A-Z,0-9
  • longopts: 选项数组,每个数组元素会被作为选项字符串,匹配了以两个连字符(–)传入到脚本的选项,比如opt识别--opt
  • optind(>=PHP7.1.0): 如果存在该参数,那么参数解析停止的索引将写入该变量

options字符串可能包含一下元素:

  • 单独的字符(不接受值)
  • 后面跟随冒号的字符(此选项需要值)
  • 后面跟随两个冒号的字符(此选项的值可选)

选项的值是字符串后的第一个参数,值和选项之间可以没有前置空格,选项值中不可以包含空格。

getopt()示例和用法

基本用法示例,PHP文件arg_test.php如下:

<?php
options = getopt('a:b:cde');
var_dump(options);

以下面的命令启动:

php arg_test.php -aav -c -d -b bv -f

则输出为:

array(4) {
  ["a"]=>
  string(2) "av"
  ["c"]=>
  bool(false)
  ["d"]=>
  bool(false)
  ["b"]=>
  string(2) "bv"
}

可以注意到使用getopt(options)时的几个点:

  • options中的参数顺序和命令行的参数顺序不用相同
  • 选项和值之间是否有空格都能区分值
  • options中单独的字符,返回的参数列表的key是选项,valuefalse
  • options中没有指定的选项,及时命令行传入,也不会返回

长选项示例,arg_test.php:

<?php
// Script arg_test.php
shortopts  = "";shortopts .= "f:";  // Required value
shortopts .= "v::"; // Optional valueshortopts .= "abc"; // These options do not accept values

longopts  = array(
    "required:",     // Required value
    "optional::",    // Optional value
    "option",        // No value
    "opt",           // No value
);options = getopt(shortopts,longopts);
var_dump($options);

以下面命令启动:

php arg_test.php -f "value for f" -v -a --required value --optional="optional value" --option

输出为:

array(6) {
  ["f"]=>
  string(11) "value for f"
  ["v"]=>
  bool(false)
  ["a"]=>
  bool(false)
  ["required"]=>
  string(5) "value"
  ["optional"]=>
  string(14) "optional value"
  ["option"]=>
  bool(false)
}

同一个选项可以传递多次,并且可以合并不同的选项:

<?php
// Script arg_test.php
options = getopt("abc");
var_dump(options);
?>

以下面的命令启动:

php arg_test.php -aaac

输出结果为:

array(2) {
  ["a"]=>
  array(3) {
    [0]=>
    bool(false)
    [1]=>
    bool(false)
    [2]=>
    bool(false)
  }
  ["c"]=>
  bool(false)
}

最后是使用optind的例子,注意optind选项需要PHP7.1以上才支持:

<?php
// Script arg_test.php
optind = null; // 需要预先定义optind
opts = getopt('a:b:', [],optind);
var_dump(optind);pos_args = array_slice(argv,optind);
var_dump($pos_args);

以下面的命令启动:

php arg_test.php -a 1 -b 2 -- test

输出如下:

int(6)
array(1) {
  [0]=>
  string(4) "test"
}

注意上面的命令:php arg_test.php -a 1 -b 2 -- test中一共有6个参数,--test是两个参数。

命令行输入和输出

有的时候,我们需要在PHP脚本中检测用户的输入,以及输出一些提示信息给用户。这就需要用到PHP定义的标准输入输出流:

  • STDIN: 一个已打开的指向stdin的流
  • STDOUT: 一个已打开的指向stdout的流
  • STDERR: 一个已打开的指向stderr的流

可以像操作文件句柄一样操作这些标准流,而且不需要手动关闭,PHP会自行关闭。可以发现PHP对这三个常量的定义如下:

  • define(‘STDIN’, fopen(‘php://stdin’, ‘r’));
  • define(‘STDOUT’, fopen(‘php://stdout’, ‘w’));
  • define(‘STDERR’, fopen(‘php://stderr’, ‘w’));

显然这三个常量已经是打开的文件句柄,可以直接进行操作,下面是一个实例:

<?php
// 像写入文件一样,将内容显示到控制台
fwrite(STDOUT, 'please input a number between 1 and 10: ');
input = fgets(STDIN);  // 从控制台读取输入continue = true;
// 轮询输入,知道正确为止
while (continue) {
    if (input < 1 || input>10) {
        // 输出到错误流
        fwrite(STDERR, 'you input number is wrong: ' .input);
    } else {
        fwrite(STDOUT, 'you input number is correct: ' . input);continue = false;
    }
    $input = fgets(STDIN);  // 从控制台读取输入
}

交互过程如下,其中输出到STDERR的内容会标红显示:

please input a number between 1 and 10: 12
you input number is wrong: 12
34
you input number is wrong: 34
9
you input number is correct: 9

Process finished with exit code 0

PHP CLI的可行参数

PHP的命令行模式另外还提供了很多参数来控制CLI的行为,这些参数必须紧跟在php命令后面。

# 指定php.ini配置文件运行
php -c ./custom-php.ini my_script.php

下面列出几个常用的参数,详细的参数可参考官网文档

选项名称 长名称 说明
-a –interactive 交互式运行 PHP
-c –php-ini 指定一个放置 php.ini 文件的目录,或者直接指定一个自定义的 INI 文件
-n –no-php-ini 完全忽略 php.ini
-d –define 设置任何可以在 php.ini 文件中设置的配置选项的值: -d configuration_directive[=value]
-e –profile-info 激活扩展信息模式,被用于调试/测试
-f –file 解析并运行 -f 选项给定的文件名。该参数可选,可以省略,仅指明需要运行的文件名即可
-m –modules 使用该参数,PHP 将打印出内置以及已加载的 PHP 及 Zend 模块
-r –run 使用该参数可以在命令行内运行单行 PHP 代码
-B –process-begin 在处理 stdin 之前先执行 PHP 代码
-R –process-code 对每个输入行都执行 PHP 代码,此模式下有两个特殊变量:$argn(当前行内容)和$argi(当前行号)
-F –process-file 对每个输入行都执行 PHP 文件
-E –process-end 在处理完输入后执行的 PHP 代码
-v –version 将 PHP,PHP SAPI 和 Zend 的版本信息写入标准输出
-s –syntax-highlight 显示有语法高亮色彩的源代码
-z –zend-extension 加载 Zend 扩展库。如果仅给定一个文件名

喜欢 (4)
发表我的评论
取消评论
表情 贴图 加粗 删除线 居中 斜体 签到

Hi,您需要填写昵称和邮箱!

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址