PHP通常被视为Web语言,但它的命令行(CLI)能力同样强大。从简单的数据处理脚本到长期运行的守护进程,PHPCLI可以胜任各种系统编程任务。理解CLI与WebSAPI的区别,掌握CLI特有的功能和工具,可以拓展PHP的应用边界。
参考:https://qeext.cn/category/limited.html
CLISAPI的特点:与WebSAPI不同,CLI模式没有请求超时(max_execution_time无限);没有输出缓冲(默认直接输出);标准输出(STDOUT)和标准错误(STDERR)可用;以及没有$_GET、$_POST等超全局变量,取而代之的是$argv和$argc。
命令行参数解析:$argv数组包含所有命令行参数,$argv[0]是脚本名称,$argv[1]是第一个参数。手动解析$argv对于简单参数可行,但复杂参数需要getopt函数。getopt支持短选项(-h)和长选项(--help),以及带值的选项(-ffile)。
现代PHP应用使用SymfonyConsole组件或LaravelArtisan构建命令行应用。这些框架提供了参数验证、自动帮助生成、命令注册等功能,大幅提升开发效率。
标准输入输出流:STDIN、STDOUT、STDERR是PHPCLI预定义的常量,指向对应的文件句柄。使用fgets(STDIN)读取用户输入,fwrite(STDOUT,"message")输出普通信息,fwrite(STDERR,"error")输出错误信息(不会影响命令管道)。
退出码:CLI脚本通过exit($code)返回退出码。0表示成功,非0表示失败。其他程序可以通过检查退出码判断脚本是否成功执行。SymfonyConsole自动处理异常退出码。
守护进程:PHP可以编写长期运行的守护进程,处理消息队列、定时任务、WebSocket连接等。守护进程需要注意:脱离终端(使用nohup或setsid);处理信号(SIGTERM、SIGHUP);避免内存泄漏(定期重启);以及日志记录(不能依赖echo)。
参考:https://vhjpe.cn/category/hufu-chengfen.html
进程控制:pcntl扩展提供了进程控制功能:pcntl_fork创建子进程;pcntl_wait等待子进程结束;pcntl_signal设置信号处理器。pcntl只能运行在类Unix系统上,不支持Windows。
POSIX扩展:posix扩展提供了更多系统编程接口:posix_getpid(获取进程ID)、posix_kill(发送信号)、posix_setsid(创建新会话,用于守护进程)。posix也是Unix专属。
多进程编程:使用pcntl_fork可以并行处理任务。主进程创建多个子进程,每个子进程处理一部分任务。需要注意:子进程会复制父进程的内存,写时复制(COW)减少开销;父进程需要等待子进程结束(避免僵尸进程);以及共享资源的同步(使用文件锁或共享内存)。
信号处理:守护进程需要优雅地响应终止信号(SIGTERM、SIGINT)。通过pcntl_signal设置信号处理器,在接收到终止信号时清理资源(关闭数据库连接、保存状态)、删除PID文件、然后退出。
PID文件:守护进程通常创建一个PID文件(如/var/run/myapp.pid),存储进程ID。启动时检查PID文件是否存在且进程是否运行,防止重复启动。停止时读取PID文件,发送信号,然后删除文件。
日志记录:守护进程不应输出到终端(因为没有终端),而应该写入日志文件或系统日志。使用error_log或Monolog记录日志。系统日志可以通过syslog函数写入,由rsyslog等服务管理。
工作队列:守护进程通常处理来自队列的任务(如Redis队列、Beanstalkd、RabbitMQ)。守护进程循环获取任务,处理,然后继续。需要注意:实现退避策略(当队列为空时等待一段时间);处理任务超时;以及失败重试机制。
内存管理:长期运行的守护进程容易产生内存泄漏。使用memory_get_usage监控内存使用;定期重启(如每1000个任务后);使用生成器处理大数据集;以及避免循环中累积数组。
性能分析:使用Xdebug或Blackfire分析守护进程的性能,注意长时间运行的Profiler可能产生巨大日志文件。更好的做法是在开发环境重现问题,或使用采样分析器。
参考:https://xgmoi.cn/category/yundong.html
Systemd集成:现代Linux使用Systemd管理守护进程。创建Systemd服务单元文件(.service),定义启动命令、用户、重启策略等。Systemd可以监控进程健康,自动重启崩溃的进程。PHP守护进程应响应Systemd的SIGTERM信号。
Supervisor:对于不使用Systemd的环境,Supervisor是Python编写的进程管理工具。通过配置文件定义要管理的进程,Supervisor负责启动、监控、重启。Supervisor适合开发环境或容器环境。
PHP长期运行的问题:某些扩展假设每个请求是独立环境,长期运行可能导致内存泄漏或状态污染。例如,使用mysql_connect不关闭连接会导致连接数耗尽。解决方案:使用连接池;定期重启进程;或避免使用有问题的扩展。
PHP8的改进:PHP8的JIT对长期运行的守护进程更有益,因为热点代码会被编译优化。Fibers(协程)使编写高并发守护进程更加容易,无需复杂的异步回调。PHPCLI+守护进程模式适合处理后台任务、实时数据流、WebSocket服务等场景。但需要谨慎处理内存、信号和进程管理。对于简单的定时任务,cron可能更合适。
参考:https://vhjpe.cn