浏览标签: php

编写规范的PHP命令行程序: 使用Symfony Console组件

在这篇文章里, 我会先介绍基本的PHP命令行程序开发, 然后再介绍如何使用Symfony/Console组件编写命令行程序, 最后会介绍如何使用Phar打包命令行程序.

1) 基本的命令行程序

1.1) 标准输入和输出

PHP CLI模式下有三个系统常量, 会默认打开3个文件描述符: STDIN, STDOUT, STDERR, 即标准输入, 标准输出和标准错误. 这几个文件描述符与fopen()返回的文件描述符通用, 并且同样可以被关闭. 可以被关闭这一点很重要, 因为有很多的命令行程序并不需要对这几个输入输出设备进行操作, 特别是当命令行程序是多线程(多进程)服务端程序是, 保持他们而不关闭会有一定性能开销.

PHP还支持这三个标准设备流, 即 php://stdin , php://stdout , php://stderr , 这样我们可以使用fopen等函数打开标准设备, 并进行相应操作.

在Web开发中我们使用的echo, print_r, 包括exit() 等输出的字符串均会被送至标准输入设备(STDOUT)在终端中显示. var_dump也能够在终端正确显示被打印的变量. 需要注意的是在终端中使用”\n”换行, 而不是HTML的br标签. 作为命令行程序, 建议只在终端中仅仅显示一些必要的信息, 更多的消息应该写入系统或自定义的日志中.

1.2) 获取当前执行目录

get_pwd() 函数

1.3) 获取命令行参数

1.3.1) $argv 变量

1.3.2) get_options() 函数

1.4) 命令行安全

1.4.1) SAPI 防范

由于命令行基本都是PHP CLI, 也就是用以CLI模式运行. 为了防患于未然, 我们可以检查PHP的运行模式, 防止那些以其他SAPI模式启动PHP程序(特别是CGI/FastCGI/Apache2Handler等)调用我们的命令行程序.

获取SAPI可以通过以下二种方式:
+ php_sapi_name() 函数, 返回接口类型的小写字符串, [php language=”.net”]/php
+ PHP_SAPI 常量, 与php_sapi_name()函数具有相同的值

2) 使用Symfony/Console组件

一个标准的命令行程序一般需要支持长短参数, 查看版本和帮助信息, 查看支持的命令和参数选项等功能. 如果这些功能全部从零构建, 将花费大量时间. 还好我们有Symfony/Console库来帮助我们构建基础的命令行环境, 这样我们就可以专注于命令的功能开发.

使用Symfony/Console组件编写命令行应用和使用框架编写Web Mvc应用很像.

2.1) 约定

3) 使用Phar打包臃肿的命令行程序

无论是自行开发命令行程序, 还是基于Symfony/Console组件, 绝大多数情况下我们都会建立多个php文件. 如果能将这些文件合并成一个文件, 使用和拷贝将十分方便.

如果决定使用Phar打包PHP程序, 最大的问题是如何处理依赖项目. 绝大多数现代的PHP程序都已经使用了Composer作为依赖管理工具. 如果不将依赖项目打包, 则最终phar文件并不能直接使用. 如果打包依赖, 则会造成phar文件过大.

为了解决这个问题, 我开发了一个按需加载的项目(composer-phar). 使用这个项目不会将依赖项目打包, 而是在生成的phar文件中放置依赖关系(通常是composer.json). 当phar文件执行, 它会自动注册一个类文件查找路径, 当发现缺少相关依赖时, 它会收集所有缺失依赖并提示用户确认下载相关依赖. 所以它更像是以Composer为基础的Linux发行版包管理系统.

关于Composer-phar, 请参考我的另一篇文章《在phar包中处理Composer依赖库:使用Composer-Phar》。 值得一提的是, Composer-Phar这一项目也是基于Symfony/Console开发的命令行程序, 具有一定参考价值. GitHub.

感谢你的阅读!本文系原创文章,出自 行间小筑 并遵循 自由转载-非商用-非衍生-保持署名(创意共享3.0许可证),转载时请注明出处和本文链接:https://panlatent.com/archives/use-symfony-console