PHP 命令行模式

PHP 命令行

PHP 从 4.3.0 版本开始给我们提供了 CLI(Command Line Interface) ,即命令行接口。

1 快速上手

假如有如下代码:

<?php

echo "My name's fingerQin!\n";

将其保存任意文件名的文件。我们这里是 test.php。

执行该脚本:

[root@localhost ~]# clear
[root@localhost ~]# php test.php 
My name's fingerQin!

我这里是在 Linux 环境下的命令行终端执行该脚本。

注意:

1)首要确定你已经在系统当中安装了 PHP 并且已经将 PHP 命令设置到了系统环境变量当中。

2)Window 系统下请用命令行提示符工具来运行。

2 CLI 与 CGI 的区别

CLI 是 PHP 专门提供给我们与命令行交互的工具。CGI 是 PHP 提供给 Web Server 通信的接口。所以,在我们的 PHP 项目开发当中,很多框架都会提供一个 Web 模式的入口,一个 CLI 的入口。

  • 与 CGI 不同,CLI 其输出没有任何头(Header)信息。
  • CLI 模式下,出错时输出纯文本的错误信息(非 HTML 格式)。
  • CLI 模式下,所有来自 print 和 echo 的输出将被立即写到输出端。而不作任何缓冲操作。
  • CLI 模式下,最大运行时间(max_execution_time)被设置为无限值。
  • CLI 模式下,$argc$argv 两个变量总是存在。并且携带了参数个数与实际的参数数组值。
  • CLI SAPI 不会将当前目录改为已运行的脚本所在的目录。
  • CLI 模式提供了几个专用常量:STDIN、STDOUT、STDERR。

注意:配置文件(php.ini)当中 html_errors、implicit_flush、max_execution_time、register_argc_argv 对其修改对 CLI 模式下运行的 PHP 来说没有任意作用。因为,CLI 启动的时候会重置这些值。

接下来我们对它们的这些区别进行分开说明。

2.1)CLI 模式没有任何头(Header)信息。

因其 CLI 是命令行下交互的接口。Header 头是 HTTP 协议定义的一部分。在 CGI 模式才支持这些交互协议。所以,Header 头信息对 CLI 模式来说并没有任何意义。所以,CLI 模式不会有任何头信息。PHP 也没有提供相应的配置来开启支持头信息的输出。

2.2)CLI 模式常用的输出会立即写到输出端,而不作任何缓冲操作。

在 CGI 模式下,因其要考虑到性能以及通信的问题。所以,服务器端的输出是一次性执行结束输出到客户端。但是, CLI 模式下通常不会有这种的需求。

如果希望延缓或控制标准输出,仍然可以使用 output buffering 设置项改变其行为。

验证:

<?php

echo "My name's fingerQin!\n";
sleep(3);
echo "ok\n";

假如有如上 PHP 代码,在 CLI 模式下,我们会发现会立即输出结果。并会不等待 3 秒再输出。如果是在 CGI 模式下,会等待 3 秒再输出结果。这就是它们的区别。

注:该区别是受配置文件 php.ini 中 implicit_flush 控制。在 CLI 模式下此值始终为 TRUE。

2.3)CLI 模式下,出错时输出纯文本的错误信息(非 HTML 格式)。

PHP 在出错时,输出的错误信息默认格式是受 php.ini 中 html_errors 控制。在 CLI 模式下此值始终为 FALSE。因为,无意义的 HTML 标记符会使得出错信息很凌乱,所以在外壳下阅读报错信息是十分困难的。

2.4)CLI 模式下,最大运行时间(max_execution_time)被设置为无限值。

因为,通常在 CLI 模式下运行的程序可能出现无穷运行下去的可能性。所以,最大运行时间被设置为了无限值。这个跟 WEB 开发下应用程序可能只需要几秒钟。

PHP 配置文件当中 max_execution_time 在 CLI 模式下始终为 0。即执行时间无限制。

2.5)CLI 模式下,$argc$argv 两个变量总是存在。并且携带了参数个数与实际的参数数组值。

这两个值是 CLI 模式下专属的值。在 CLI 启动的时候这两个变量就已经被初始化。$argc 保存的是当前命令行的参数个数,$argv 保存的是命令的参数值,且类型为数组。

所以,在 CLI 开发时,不要对这两个变量进行任何的写操作。除非你明确知道自己这样做的后果。

2.6)CLI SAPI 不会将当前目录改为已运行的脚本所在的目录。

这个怎么理解呢?比如,我们在为 /home 的目录下,用 PHP 命令执行了某个 PHP 脚本。但是,此时通过 getcwd() 得到的结果不是 /home 而是脚本所在的目录。

总之,我们只要记住当前目录始终为脚本所在目录即可。

2.7)CLI 模式提供了几个专用常量:STDIN、STDOUT、STDERR。

有了以上常量,就无需自己建立指向诸如 stderr 的流,只需简单的使用这些常量来代替流指向:

php -r 'fwrite(STDERR, "stderr\n");'

3 运行 PHP 代码的三种方式

CLI SAPI 模块有以下三种不同的方法来获取要运行的 PHP 代码:

3.1)让 PHP 运行指定文件

php my_script.php

php -f my_script.php

以上两种方法(使用或不使用 -f 参数)都能够运行给定的 my_script.php 文件。可以选择任何文件来运行,指定的 PHP 脚本并非必须要以 .php为扩展名,它们可以有任意的文件名和扩展名。

3.2)在命令行直接运行 PHP 代码

php -r 'print_r(get_defined_constants());'

在使用这种方法时,请注意外壳变量的替代及引号的使用。

请仔细阅读以上范例,在运行代码时没有开始和结束的标记符!加上 -r 参数后,这些标记符是不需要的,加上它们会导致语法错误。

3.3)通过标准输入(stdin)提供需要运行的 PHP 代码

以上用法提供了非常强大的功能,使得可以如下范例所示,动态地生成 PHP 代码并通过命令行运行这些代码:

$ some_application | some_filter | php | sort -u >final_output.txt

和所有的外壳应用程序一样,PHP 的二进制文件(php.exe 文件)及其运行的 PHP 脚本能够接受一系列的参数。PHP 没有限制传送给脚本程序的参数的个数(外壳程序对命令行的字符数有限制,但通常都不会超过该限制)。传递给脚本的参数可在全局变量 $argv 中获取。该数组中下标为零的成员为脚本的名称(当 PHP 代码来自标准输入获直接用 -r 参数以命令行方式运行时,该名称为“-”)。另外,全局变量 $argc 存有 $argv 数组中成员变量的个数(而非传送给脚本程序的参数的个数)。

只要传送给脚本的参数不是以 - 符号开头,就无需过多的注意什么。向脚本传送以 - 开头的参数会导致错误,因为 PHP 会认为应该由它自身来处理这些参数。可以用参数列表分隔符 -- 来解决这个问题。在 PHP 解析完参数后,该符号后所有的参数将会被原样传送给脚本程序。

4 PHP 命令参数说明

参数长名称说明
-a--interactive交互式运行 PHP。如果编译 PHP 时加入了 Readline 扩展(Windows 下不可用),那将会得到一个很好的外壳,包括一个自动完成的功能(例如可以在键入变量名的时候,按下 TAB 键,PHP 会自动完成该变量名)以及命令历史记录,可以用上下键来访问。历史记录存在 ~/.php_history 文件中。
-c--php-ini用该参数,可以指定一个放置 php.ini 文件的目录,或者直接指定一个自定义的 INI 文件(其文件名可以不是 php.ini),例如:php -c /custom/directory/ my_script.phpphp -c /custom/directory/custom-file.ini my_script.php
-n--no-php-ini完全忽略 php.ini。此参数在 PHP 4.3.0 以后有效。
-d--define用该参数可以自行设置任何可以在 php.ini 文件中设置的配置选项的值,其语法为: -d configuration_directive[=value]
-e--profile-info激活扩展信息模式,被用于调试/测试。
-f--file解析并运行 -f 选项给定的文件名。该参数为可选参数,可以省略,仅指明需要运行的文件名即可。
-i--info该命令行参数会调用 phpinfo() 函数并显示出结果。如果 PHP 没有正常工作,建议执行 php -i 命令来查看在信息表格之前或者对应的地方是否有任何错误信息输出。请注意当使用 CGI 摸索时,输出的内容为 HTML 格式,因此输出的信息篇幅较大。
-l--syntax-check该参数提供了对指定 PHP 代码进行语法检查的方便的方法。如果成功,则向标准输出写入 No syntax errors detected in <filename> 字符串,并且外壳返回值为 0。如果失败,则输出 Errors parsing <filename> 以及内部解析器错误信息到标准输出,同时外壳返回值将别设置为 255
该参数将无法检查致命错误(如未定义函数),如果也希望检测致命错误,请使用 -f 参数。 该参数不能和 -r 一同使用。
-m--modules使用该参数,PHP 将打印出内置以及已加载的 PHP 及 Zend 模块。
-r--run使用该参数可以在命令行内运行单行 PHP 代码。无需加上 PHP 的起始和结束标识符(<?php 和 ?>),否则将会导致语法解析错误。
-B--process-begin在处理 stdin 之前先执行 PHP 代码。PHP 5 新加。
-R--process-code对每个输入行都执行 PHP 代码。PHP 5 新加。 此模式下有两个特殊变量:$argn 和 $argi。$argn 包含 PHP 当前处理的行内容,而 $argi 则包含该行号。
-F--process-file对每个输入行都执行 PHP 文件。PHP 5 新加。
-E--process-end在处理完输入后执行的 PHP 代码。PHP 5 新加。
-s--syntax-highlight显示有语法高亮色彩的源代码。 感觉没啥用。
-v--version将 PHP,PHP SAPI 和 Zend 的版本信息写入标准输出。
-w--strip显示除去了注释和多余空白的源代码。
-z--zend-extension加载 Zend 扩展库。如果仅给定一个文件名,PHP 将试图从当前系统扩展库的默认路径(在 Linux 系统下,该路径通常由 /etc/ld.so.conf 指定)加载该扩展库。如果用一个绝对路径指定文件名,则不会使用系统的扩展库默认路径。如果用相对路径指定的文件名,则 PHP 仅试图在当前目录的相对目录加载扩展库。
--ini 显示配置文件名称。
--rf 显示指定方法相关信息。对语言结构无效。echo、print 等语言结构不可以。
--rc 显示指定类相关信息。
--re 显示指定扩展相关信息。
--rz 显示指定 Zend 扩展相关信息。
--ri 显示指定扩展的配置信息。

5 实际应用案例

5.1)查看 PHP 版本

[root@localhost test]# php -v
PHP 7.1.12 (cli) (built: Nov 29 2017 11:18:30) ( NTS )
Copyright (c) 1997-2017 The PHP Group
Zend Engine v3.1.0, Copyright (c) 1998-2017 Zend Technologies
    with Zend OPcache v7.1.12, Copyright (c) 1999-2017, by Zend Technologies
    with Xdebug v2.6.0, Copyright (c) 2002-2018, by Derick Rethans

5.2)查看 PHP 扩展列表

[root@localhost test]# php -m
[PHP Modules]
bcmath
Core
ctype
curl
date
dom
event
exif
fileinfo
filter
ftp
gd
......

通过这种方式,我们就知道了 PHP 已经安装启用了哪些扩展。

5.3)查看指定配置信息

假如,我们现在想快速查看 session 相关的配置信息。可通过如下方式操作:

[root@localhost test]# php -i|grep session
session
session.auto_start => Off => Off
session.cache_expire => 180 => 180
session.cache_limiter => nocache => nocache
session.cookie_domain => no value => no value
session.cookie_httponly => Off => Off
session.cookie_lifetime => 0 => 0
session.cookie_path => / => /
session.cookie_secure => Off => Off
session.gc_divisor => 1000 => 1000
session.gc_maxlifetime => 1440 => 1440
session.gc_probability => 1 => 1
session.lazy_write => On => On
session.name => PHPSESSID => PHPSESSID
session.referer_check => no value => no value
session.save_handler => files => files
session.save_path => no value => no value
session.serialize_handler => php => php
session.sid_bits_per_character => 5 => 5
session.sid_length => 26 => 26
session.upload_progress.cleanup => On => On
session.upload_progress.enabled => On => On
session.upload_progress.freq => 1% => 1%
session.upload_progress.min_freq => 1 => 1
session.upload_progress.name => PHP_SESSION_UPLOAD_PROGRESS => PHP_SESSION_UPLOAD_PROGRESS
session.upload_progress.prefix => upload_progress_ => upload_progress_
session.use_cookies => On => On
session.use_only_cookies => On => On
session.use_strict_mode => Off => Off
session.use_trans_sid => 0 => 0
session.trans_sid_hosts => no value => no value
session.trans_sid_tags => a=href,area=href,frame=src,form= => a=href,area=href,frame=src,form=

5.4)验证 PHP 脚本是否存在语法错误

这个功能通常用于一些 PHP IDE 集成开发工具,它们用来检查当前 PHP 脚本是否存在语法错误。另外,有些 PHP 开发者在 Linux 命令行工作的时候,想快速检查自己编写的代码是否存在语法错误。

[root@localhost test]# php -l test.php 
No syntax errors detected in test.php

但是,我在使用的时候,发现连 notice 级别的错误都检查不出来。不知道是不是姿势不对?还是这个命令还不够成熟。

5.5)查看 PHP 使用的配置文件

有时候,我们不知道 PHP 加载的 PHP 文件的位置。可以通过如下命令快速获悉:

[root@localhost test]# php --ini
Configuration File (php.ini) Path: /usr/local/php71/etc
Loaded Configuration File:         /usr/local/php71/etc/php.ini
Scan for additional .ini files in: /usr/local/php71/etc/php.d
Additional .ini files parsed:      (none)

5.6)查看是否存在内置方法

存在:

[root@localhost test]# php --rf strlen
Function [ <internal:Core> function strlen ] {

  - Parameters [1] {
    Parameter #0 [ <required> $str ]
  }
}

不存在:

[root@localhost test]# php --rf strlens
Exception: Function strlens() does not exist

注意:语言结构通过这种方式是会被认为不存在该方法的。所以,该方法也可以用来判决是否为语言结构。

[root@localhost test]# php --rf echo
Exception: Function echo() does not exist

5.7)查看是否存在内置类

[root@localhost test]# php --rc PDO
Class [ <internal:PDO> class PDO ] {

  - Constants [86] {
    Constant [ public integer PARAM_BOOL ] { 5 }
    Constant [ public integer PARAM_NULL ] { 0 }
    Constant [ public integer PARAM_INT ] { 1 }
    Constant [ public integer PARAM_STR ] { 2 }
    Constant [ public integer PARAM_LOB ] { 3 }
    Constant [ public integer PARAM_STMT ] { 4 }
    Constant [ public integer PARAM_INPUT_OUTPUT ] { 2147483648 }
    Constant [ public integer PARAM_EVT_ALLOC ] { 0 }
    Constant [ public integer PARAM_EVT_FREE ] { 1 }
    Constant [ public integer PARAM_EVT_EXEC_PRE ] { 2 }
    Constant [ public integer PARAM_EVT_EXEC_POST ] { 3 }
    Constant [ public integer PARAM_EVT_FETCH_PRE ] { 4 }
    ......

当然该命令本身是用来查看类定义的。

不存在类的情况会如下提示:

[root@localhost test]# php --rc PDO_EXCEPTION
Exception: Class PDO_EXCEPTION does not exist

5.8)查看扩展是否存在

方式一:

[root@localhost test]# php --re yafs
Exception: Extension yafs does not exist

方式二:

[root@localhost test]# php -m|grep yaf
yaf

注:php --re 命令是用来查看扩展定义相关的信息的。可以自行运行查看。

5.9)查看扩展配置信息

[root@localhost test]# php --ri yaf

yaf

yaf support => enabled
Version => 3.0.6
Supports => http://pecl.php.net/package/yaf

Directive => Local Value => Master Value
yaf.library => no value => no value
yaf.action_prefer => Off => Off
yaf.lowcase_path => Off => Off
yaf.use_spl_autoload => Off => Off
yaf.forward_limit => 5 => 5
yaf.name_suffix => On => On
yaf.name_separator => no value => no value
yaf.st_compatible => Off => Off
yaf.environ => product => product
yaf.use_namespace => Off => Off

有时候,我们想知道扩展的版本,以及配置信息。可以通过这种方式快捷获知。

5.10)命令行脚本接收参数

假如有脚本 test.php 的代码如下:

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

现在我们在命令行如下执行此脚本:

$ php test.php first second

此时会输出如下内容:

array(3) {
  [0] =>
  string(9) "index.php"
  [1] =>
  string(5) "first"
  [2] =>
  string(6) "second"
}
int(3)

PHP 在命令行模式下会自动初始化两个变量:

  • $argv - 命令行所有的参数都将保存到此变量中。
  • $argc - 命令行所有的参数个数保存到此变量中。

$argv 是一个数组,第一个元素是被执行脚本的脚本名称。如果执行的时候给的路径是绝对的就是绝对路径,是相对的就是相对路径。

在 $argc 命令中仅仅保存的是参数个数。作用有限。可以用来做一些辅助的判断。比如,参数未传指定个数。

更多关于 PHP CLI 知识请阅读官方文档:http://php.net/manual/zh/features.commandline.php

博主 2011 年创建了一个《PHP 初学者官方群》,目前群成员 500 人左右。群号:168159147。为了防止广告,设置为付费入群。欢迎大家加入讨论技术!

标签: 无

发表评论: