
PHP命令行脚本开发实战PHP不仅用来做Web开发写命令行脚本也很方便。定时任务、数据处理、队列消费这些场景用PHP命令行模式再合适不过了。先说说命令行参数的处理。$argc是参数个数$argv是参数数组。getopt可以解析选项参数。php// 命令行参数解析echo 脚本名: {$argv[0]}\n;echo 参数个数: $argc\n;// 手动解析参数for ($i 1; $i $argc; $i) {echo 参数{$i}: {$argv[$i]}\n;}// 使用getopt解析选项$options getopt(u:p:h:, [host:, port:, help, verbose]);if (isset($options[help])) {echo 用法: php script.php -u 用户名 -p 密码 [--host主机]\n;echo 选项:\n;echo -u 用户名\n;echo -p 密码\n;echo -h 主机\n;echo --port 端口\n;echo --verbose 详细输出\n;exit(0);}$username $options[u] ?? null;$password $options[p] ?? null;$host $options[h] ?? $options[host] ?? localhost;$port $options[port] ?? 3306;$verbose isset($options[verbose]);if ($verbose) {echo 详细模式: 连接 $host:$port\n;}?命令行输出可以加上颜色让信息更醒目。phpclass Console{const COLORS [red \033[31m,green \033[32m,yellow \033[33m,blue \033[34m,magenta \033[35m,cyan \033[36m,white \033[37m,reset \033[0m,];const STYLES [bold \033[1m,dim \033[2m,italic \033[3m,underline \033[4m,blink \033[5m,];public static function text(string $text, string $color white): string{$colorCode self::COLORS[$color] ?? self::COLORS[white];return $colorCode . $text . self::COLORS[reset];}public static function info(string $message): void{echo self::COLORS[green] . [INFO] . self::COLORS[reset]. $message . \n;}public static function error(string $message): void{echo self::COLORS[red] . [ERROR] . self::COLORS[reset]. $message . \n;}public static function warning(string $message): void{echo self::COLORS[yellow] . [WARNING] . self::COLORS[reset]. $message . \n;}public static function success(string $message): void{echo self::COLORS[green] . [SUCCESS] . $message . self::COLORS[reset] . \n;}public static function table(array $headers, array $rows): void{// 计算列宽$widths [];foreach ($headers as $i $header) {$widths[$i] strlen($header);foreach ($rows as $row) {$widths[$i] max($widths[$i], strlen((string)($row[$i] ?? )));}}// 输出表头$separator ;foreach ($widths as $w) {$separator . str_repeat(-, $w 2) . ;}echo $separator . \n;echo |;foreach ($headers as $i $header) {echo . str_pad($header, $widths[$i]) . |;}echo \n;echo $separator . \n;// 输出数据行foreach ($rows as $row) {echo |;foreach ($row as $i $cell) {echo . str_pad((string)$cell, $widths[$i]) . |;}echo \n;}echo $separator . \n;}public static function progressBar(int $current, int $total, int $width 50): void{$percent round($current / $total * 100);$filled round($width * $current / $total);$bar str_repeat(, $filled) . str_repeat( , $width - $filled);printf(\r进度: [%s] %d%% (%d/%d), $bar, $percent, $current, $total);if ($current $total) {echo \n;}}public static function confirm(string $message): bool{echo self::COLORS[yellow] . $message (y/N): . self::COLORS[reset];$input trim(fgets(STDIN));return strtolower($input) y || strtolower($input) yes;}public static function input(string $prompt, string $default ): string{$defaultText $default ? [$default] : ;echo $prompt$defaultText: ;$input trim(fgets(STDIN));return $input ?: $default;}}Console::info(系统启动);Console::warning(磁盘空间不足);Console::error(连接失败);Console::success(操作完成);echo Console::text(红色文字, red) . \n;echo Console::text(蓝色粗体, blue) . \n;Console::table([ID, 姓名, 年龄, 城市],[[1, 张三, 28, 北京],[2, 李四, 35, 上海],[3, 王五, 22, 广州],]);for ($i 1; $i 100; $i) {Console::progressBar($i, 100);usleep(30000);}?管线和重定向让命令行脚本可以组合使用。php// 从标准输入读取$input file_get_contents(php://stdin);$lines explode(\n, trim($input));echo 读取了 . count($lines) . 行数据\n;// 处理每行数据$processed array_map(function ($line) {$line trim($line);if (empty($line)) return null;return strtoupper($line);}, $lines);$processed array_filter($processed);// 输出到标准输出foreach ($processed as $item) {echo $item . \n;}// 输出到标准错误fwrite(STDERR, 处理完成\n);?命令行脚本的生命周期管理和错误处理比Web脚本更重要。php// 信号处理declare(ticks 1);pcntl_signal(SIGTERM, signalHandler);pcntl_signal(SIGINT, signalHandler);$running true;function signalHandler(int $signal): void{global $running;echo \n收到信号: $signal\n;echo 正在清理...\n;$running false;}// 内存管理和超时控制set_time_limit(0); // CLI模式通常不限执行时间$startTime time();$maxRuntime 3600; // 最长运行1小时echo 开始处理...\n;$count 0;while ($running) {$count;// 检查运行时间if (time() - $startTime $maxRuntime) {echo 运行超时\n;break;}// 检查内存if (memory_get_usage(true) 100 * 1024 * 1024) {echo 内存超限\n;break;}// 模拟处理if ($count 1000) {$running false;echo 处理完成\n;}}echo 总共处理: $count 条\n;?定时任务也是命令行脚本的常见用途。php// 简单定时任务调度器class Scheduler{private array $tasks [];public function addTask(string $name, callable $task, int $interval): void{$this-tasks[] [name $name,task $task,interval $interval,last_run 0,];}public function run(): void{echo 调度器启动\n;while (true) {$now time();foreach ($this-tasks as $task) {if ($now - $task[last_run] $task[interval]) {$task[last_run] $now;echo 执行任务: {$task[name]}\n;try {($task[task])();} catch (Exception $e) {echo 任务失败: {$task[name]}: {$e-getMessage()}\n;}}}unset($task);sleep(1);}}}$scheduler new Scheduler();$scheduler-addTask(数据库备份, function () {echo 备份完成\n;}, 3600);$scheduler-addTask(清理日志, function () {echo 日志清理完成\n;}, 7200);?命令行脚本在PHP开发中占有一席之地。定时任务用cron加PHP脚本数据处理用管道重定向队列消费用守护进程模式。掌握了命令行开发PHP的应用场景就不局限于Web了。