$argv[0]固定为脚本路径,故$argv[1]才是首个用户参数;$argc包含脚本名,判断需用>1;getopt()不支持子命令、缩写或混合解析,复杂场景应结合手动处理剩余$argv。

$argv 和 $argc 是最直接的方式,但必须跳过 $argv[0];复杂参数建议用 getopt(),否则容易漏掉长选项或中断解析。
为什么 $argv[1] 不是第一个用户参数?
因为 $argv[0] 固定为脚本路径(如 script.php),哪怕你执行的是 php script.php hello,$argv[1] 才是 hello。常见错误是写成 $argv[0] 取业务值,结果拿到脚本名还报错。
- 所有参数都是字符串,
"42"不会自动转成整型,需手动(int)或filter_var() - 带空格的参数必须用引号包裹:
php test.php "foo bar" 123→$argv[1] === "foo bar" -
$argc包含脚本名,所以判断参数数量时要用$argc > 1而不是> 0
getopt() 解析 -a 和 --long 选项时的坑
getopt() 对短选项和长选项的支持机制不同:短选项靠字符串定义(如 'f:v'),长选项必须显式传数组(如 ['file:', 'verbose']),且两者不能混在同一个调用里。
- 短选项带参必须加冒号:
'f:'表示-f value,'f'则只认-f开关本身 - 长选项带参也必须加冒号:
['input:']才能匹配--input=file.txt,否则--input=file.txt会被忽略 - 非选项参数(比如位置参数
abc def)一旦出现,getopt()就停止解析后续的-x或--xxx,它们会变成“剩余参数”留在$argv里 -
getopt('', ['help'])可单独处理长选项,不干扰短选项逻辑
什么时候该放弃 getopt(),改用手动解析?
当你的 CLI 脚本需要混合使用位置参数、等号可选、空格分隔值、子命令(如 php cli.php user create --name=john)时,getopt() 就力不从心了。
-
getopt()不支持子命令层级,遇到command subcmd --flag会把subcmd当作中断点 - 它无法区分
--foo=bar和--foo bar(后者会被当成两个独立参数) - 长选项不支持缩写(
--ver≠--verbose),而用户常会这么输 - 更稳妥的做法是先用
getopt()提取已知选项,再遍历剩余$argv手动处理位置参数或自定义格式
CLI 模式下 $argv 为空的两种典型场景
不是所有 PHP 执行方式都提供 $argv。最常踩坑的是用 -r 模式或 Web SAPI 环境误当 CLI 用。
- 执行
php -r "var_dump($argv);"时,$argv恒为空数组 —— 此时只能改用环境变量($_ENV)或重写为独立脚本 - 通过 Web 服务器(如 Apache + mod_php)访问脚本时,
$argv不可用,$_SERVER['argv']也可能为空或不可靠,必须加运行模式判断:if (PHP_SAPI !== 'cli') { die('仅支持 CLI 模式'); } - 用
#!/usr/bin/env php启动的脚本,$argv[0]仍是脚本路径,不是/usr/bin/env,这点和 shell 脚本一致,无需特殊处理
真正麻烦的不是读不到参数,而是参数边界模糊:引号嵌套、等号是否必须、长选项能否缩写、子命令如何切分——这些细节没对齐,用户一输错就静默失败,调试成本远高于写解析逻辑本身。
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











