# [教程] 掌握命令行的表格输出
> ThinkPHP`V5.1.24`引入了一个新的`Table`对象,用于在命令行下面动态输出表格,刚好最新的`route:list`指令中包含了大部分表格功能的实现,所以是学习Table对象的最好示例,本篇就通过分析该指令的代码来掌握`Table`对象的用法。
[TOC=2,2]
## 初见端倪
`route:list`指令是一个用于查看路由定义的指令,我们先运行下看下在命令行下输出的表格效果,有个感性的认识。
随便在你的路由定义文件中定义一些路由规则,例如下面定义了一个闭包路由、一个资源路由和一个普通路由。
~~~
Route::get('think', function () {
return 'hello,ThinkPHP5!';
});
Route::resource('blog', 'Blog');
Route::get('hello/:name', 'index/hello');
~~~
在命令行下面(切换到项目根目录)执行:
~~~
php think route:list
~~~
你会看到下面的表格输出:
![](https://box.kancloud.cn/3239aeaf0578b814c4df45a095d008c2_541x234.png)
> 通过这个指令你可以清晰看到每个资源路由实际上会注册7个路由规则。
是不是觉得很酷😂 当然了这个指令的功能远不止这么简单,我们后面会陆续讲解。
## 指令寻址
为了分析这个指令,我们先找到`route:list`指令对应的类文件(指令寻址),打开`\think\Console`类,找到`defaultCommands`属性
![](https://box.kancloud.cn/7e7549a22f5e05dc0310ed2e5b21a293_758x386.png)
这个属性定义了核心内置的所有指令,数组的索引就是指令名,键值就代表了该指令对应的完整类名。可以看到`route:list`指令对应的就是`think\console\command\RouteList`类,接下来就来给大家分析下这个指令的代码实现。
## 指令定义
任何一个合法的指令类都必须继承系统的`think\console\Command`类,`RouteList`类一共130行左右代码,所以基本上很容易看明白,首先我们看第一个`configure`方法,该方法的作用就是配置当前指令的用法。
![](https://box.kancloud.cn/5636d6d1f8ace1be12a8e34531bfe78b_861x180.png)
`setName`方法就是指定当前类的指令名(注意指令名尽量使用小写,并且不要包含除`:`、`_`之外的特殊字符)。
`addArgument`方法是添加指令参数,这里添加的style参数表示表格输出的样式。该方法的参数可以在`think\console\input\Argument`类的构造方法中查看。
![](https://box.kancloud.cn/b297863562bf5288d9e42645b5646d1d_848x473.png)
第二个参数表示参数的类型必须或者可选,对于`route:list`指令而言,这个参数是可选的,因此传入`Argument::OPTIONAL`,并且设置了该参赛的默认值是`default`。
`addOption`方法是添加指令选项,这里添加了`sort`和`more`两个选项,并且分别设置了简写。
具体用法则可以在`think\console\input\Option`类的构造方法中看到。
![](https://box.kancloud.cn/7e5e02b824e8fc572b5a0bb0c040fba2_1089x520.png)
`setDescription`方法用于指定当前指令的描述信息。
我们可以用`-h`选项来查看下指令配置的最终效果(可以对任何指令使用`-h`或者`--help`选项来查看指令帮助)
~~~
php think route:list -h
~~~
![](https://box.kancloud.cn/adbc7ff60c5bcf81de2eabc2545fae24_1000x288.png)
## 拨云见日
第二个方法是`execute`方法,该方法会在指令在执行的时候自动调用。
![](https://box.kancloud.cn/f422d46bad72e2094d7f57b9a3ef3730_748x229.png)
可以看到`route:list`指令的执行操作很简单,获取路由定义列表的内容(这个时候会同时在命令行输出)后就写入一个`route_list.php`文件中。所有的真相都在`getRouteList()`这个方法里面了,这也是本文的关键所在。
再来深入分析`getRouteList()`方法。
![](https://box.kancloud.cn/fbad1631b598e633e6dab688395859ac_445x37.png)
这行代码可能很多人不明白,我先解释下。由于ThinkPHP`5.1`的路由采用延时解析机制,如果不开启测试模式的话,可能没有办法获取到所有的路由规则的,尤其是当使用了路由分组和资源路由的时候,实际上都是在路由匹配后才会真正解析分组或者资源路由下面的实际路由规则。而`setTestMode(true)`的作用就是让路由规则实时解析,这样我们才能获取到所有的路由规则。
![](https://box.kancloud.cn/01e4fed9f0b2a0ea3347684308a7b15f_536x325.png)
这段代码的作用则是获取所有的路由定义文件,如果采用了配置数组方式定义的话也会批量导入。
>[danger] 配置数组方式定义路由规则在`5.1`版本中已经不再建议,在下一个大版本中就会废除,所以尽量不要使用数组方式定义,而改为方法定义
![](https://box.kancloud.cn/9e1b2886e93684fe37d9c502137ee3af_1103x128.png)
这段代码的作用是在开启注解路由的情况下进行注解路由的解析,有兴趣的朋友可以通过跟踪`think\Build`类的`buildRoute`方法的实现深入了解下注解路由是如何实现的,由于不再文本的讲解范畴,所以暂且不表。
## 表格输出
前面铺垫了那么多,接下来就要进入正题了(原来讲了这么多废话😄)
![](https://box.kancloud.cn/526e408ca39f80c514a4d3f748784e4c_804x200.png)
这段代码首先实例化了一个`think\console\Table`类,并通过`setHeader`方法设置输出的表头信息。
`setHeader`方法的参数可以参考`Table`类的代码
![](https://box.kancloud.cn/37418c61a0bcfd7e876f7e453d2cb27a_796x306.png)
第一个参数是表头信息(数组),其实还有第二个参数可以控制表头信息的对齐方式,默认是左对齐,如果要让表头信息居中对齐或者居右,可以使用下面的方式
把
~~~
$table->setHeader($header);
~~~
改为居中对齐
~~~
// 表头居中对齐
$table->setHeader($header, Table::ALIGN_CENTER);
~~~
再次运行指令后,输出的效果变为:
![](https://box.kancloud.cn/d70b1c8ce79e3edb4ebe30004947316e_533x231.png)
或者居右对齐
~~~
// 表头居右对齐
$table->setHeader($header, Table::ALIGN_RIGHT);
~~~
![](https://box.kancloud.cn/e125e6e11e4282b1277b01de1ce0ab80_532x234.png)
这里判断是否传入了`more`选项(参考前面讲到的指令配置部分),如果有则附加额外的表头信息。也就是说,如果使用了`--more`或者`-m`你就能看到关于路由的详细信息(增加了路由参数和变量规则)。
![](https://box.kancloud.cn/b5c399da60be44317a6623c2cf995cf3_815x232.png)
![](https://box.kancloud.cn/4d1adf6193369c31876defb08dd88ec9_890x358.png)
这段代码的作用是获取路由定义列表数据,事实上,`think\Route`类已经封装好了一个获取已经定义的路由规则列表方法`getRuleList()`,所以在指令中我们不需要自己实现。有兴趣的朋友,可以参考下`think\route\RuleName`类的`setRule()`方法和`getRuleList()`两个方法的代码实现,在此略过不提。
由于`getRouteList()`方法获取的数据是一个三维数组,我们需要重新进行封装为一个Table类可以输出的二维数组格式。同样在封装单元格数据的时候也判断是否使用了`--more`选项而使用不同的数据。最终封装到的二维数组保存到`rows`数组变量中。
![](https://box.kancloud.cn/e0111f50cfd72167e26b1bcef61ca4fa_526x305.png)
这段代码的作用如果传入了`--sort`选项,则对二维数组进行指定排序排序。
排序的指定方式有两种:一种是直接从0开始的序号,0表示对第一列排序,1表示对第二列排序,以此类推,另外一种方式是对指定的列名进行排序。
例如我们要对第三列(请求类型)进行排序,可以用
![](https://box.kancloud.cn/39bdebbf243350658a74d47c4014f992_528x230.png)
由于这样不够直观,系统还提供了第二种方式
![](https://box.kancloud.cn/d0f83a39b2e121c3cf8fc2275eaad33b_526x232.png)
![](https://box.kancloud.cn/604a2d1b868648359614bbf659cecfa4_387x45.png)
这段代码的作用就是给`Table`类实例对象设置表格数据,和`setHeader()`方法一样,`setRows()`方法也支持指定对齐方式。
![](https://box.kancloud.cn/375bc545ef4a60bb73c94e2e3f4c67b1_787x333.png)
如果我们把
~~~
$table->setRows($rows);
~~~
改成:
~~~
// 表格数据居右对齐
$table->setRows($rows, Table::ALIGN_RIGHT);
~~~
再次运行指令后的输出效果如图:
![](https://box.kancloud.cn/1031bb8fed73ffb21fa584b5737e513c_528x230.png)
![](https://box.kancloud.cn/e86646c52e07fed240f129dd6ede7cd4_471x105.png)
这段代码的作用是使用`setStyle()`方法指定表格输出的样式,我们之前看到的都是默认的样式输出。
现在我们来看下可以支持哪些样式,
![](https://box.kancloud.cn/cf0da2c5a73e913a8c2fdce03a957f88_521x225.png)
![](https://box.kancloud.cn/e7cabd9326d6a01974400b16033ff335_522x227.png)
![](https://box.kancloud.cn/b05eab975397f68939ac4f6cc0ed315d_521x219.png)
通过查看Table类的源码,我们可以看到支持的样式可以包括:
样式名|描述
---|---
default|默认样式
compact|没有任何表格边框输出
markdown|MARKDOWN格式输出表格
borderless|没有左右边框的表格输出
box|闭合边框输出表格
box-double|双线闭合边框输出表格
> 如果没有指定表格样式或者指定了一个不存在的样式,则默认采用`default`样式风格。
>
最后一步是渲染输出表格,这是调用的是`Command`类封装好的`table`方法,当然你也可以自己参考该方法实现。
![](https://box.kancloud.cn/4fad3369607acacfeb116f822fceef49_298x52.png)
下面的代码是`Command`类的`table`方法的实现代码。
![](https://box.kancloud.cn/008c3ec9e5699f3aa2847898be7b3798_402x245.png)
该方法在命令行输出表格之后返回了渲染的表格内容,是为了便于后面写入路由定义列表的内容到`route_list.php`文件,可以随时查看。
有时候需要实现一个跨行跨列的输出,例如实现一个跨列的单元格,我们在
~~~
$table->setRows($rows);
~~~
后面添加如下代码:
~~~
// 跨列数据直接传入字符串
$table->addRow('Extra Route List');
$table->addRow(['test/:name', 'index/test', '*', 'test', '']);
~~~
现在运行指令后输出效果如图:
![](https://box.kancloud.cn/d97bab849e799a5a9130ef2d62056628_526x296.png)
> 目前Table尚不支持跨部分列的表格输出
## 总结
总结下来,`Table`类的用法其实很简单
~~~
// 实例化一个Table对象
$table = new Table();
// 设置表头(可选)
$table->setHeader();
// 设置表格数据
$table->setRows();
// 添加单行数据(可选)
$table->addRow();
// 设置表格样式(可选)
$table->setStyle();
// 渲染表格输出
$content = $table->render();
~~~
其实不仅仅是用于命令行输出,你还可以进行文件写入的时候生成表格数据内容。
- 值得升级到5.1的18个理由
- 5.1.7版本新特性
- JSON字段类型在ORM中的使用
- 文件下载响应对象
- 教你使用5.1的数组对象查询
- 模型三大利器之一:搜索器
- 在ThinkPHP中使用Yaconf
- 掌握命令行的表格输出
- 5.1.25查询参数绑定的改进
- ThinkPHP安全规范指引
- 巧用数据集的排序功能实现统计排序
- think-orm ——基于5.1的独立ORM库
- think-template——基于ThinkPHP的独立模板引擎
- ThinkPHP5.1.26版本发布——修正版本,包含安全更新
- ThinkPHP5.0和3.2再发安全更新
- 官宣:ThinkPHP发布首个LTS版本
- 你真的了解Db类和模型的正确使用姿势么?
- 如何更有效的记录和管理日志
- 模型三大利器之二:修改器
- ThinkPHP5.1.28版本发布——修正上一版本问题,改进关联查询
- 模型三大利器之三:获取器
- API版本控制的几种思路
- ThinkPHP5.2第一个Beta版本发布测试
- 让你少犯错的数据查询基本原则
- ThinkPHP发布5.1.29版本——常规更新
- 这15个好习惯让你更容易升级到5.2
- 如何有效提高ThinkPHP的应用性能
- 让你提高开发效率的查询技巧
- 模型关联查询不完全指南
- 5.2发布Beta2版本——统一和精简大量用法
- ThinkPHP发布5.1.30版本——支持微秒时间字段写入
- ThinkPHP的数据缓存使用
- ThinkPHP5.2安装及入口文件
- ThinkPHP荣获2018 年度最受欢迎中国开源开发框架第1名
- 5.1路由使用心得技巧
- ThinkPHP5.*版本发布安全更新
- ThinkPHP项目及代码规范指北
- 5.2版本的设计规范指导
- ThinkPHP5.1.32版本发布——圣诞快乐
- 利用Trait特性给模型增加乐观锁功能
- 5.2数据库和模型的变化(摘要)
- ThinkPHP模板引擎实现和常见问题
- ThinkPHP5.0.24版本发布——安全更新
- 不忘初心,方得始终——ThinkPHP十三周年报告
- ThinkPHP5+相关资源汇总
- 异步社区ThinkPHP周年庆专享优惠活动
- 5.2路由的调整和改进
- ThinkPHP发布5.1.33版本——包含安全更新
- ThinkPHP扩展开发指南
- ThinkPHP发布5.2Beta3版本
- ThinkPHP发布5.1.34版本——喜迎新年
- ThinkPHP发布5.2RC1版本
- ThinkPHP发布5.1.35版本——常规更新
- 5.2配置类的调整
- 5.2时间查询的改进和优化
- 5.2RC版本升级不完全指导(仅供学习参考)
- ThinkPHP5.2版本正式变更为6.0版本
- ThinkPHP百度云云虚拟主机专享免费活动
- 事件系统以及查询事件、模型事件的使用
- ThinkPHP6.0RC2版本发布——架构升级、精简核心
- ThinkPHP5.1.36LTS版本发布——常规更新
- 新版Session和Cookie设计变化
- ThinkPHP5.1.37版本发布——常规更新
- ThinkPHP6.0RC3版本发布——细节完善,体验优化
- 6.0中间件使用详解
- Composer各大厂商镜像地址
- ThinkPHP6.0发布计划公告
- 「ThinkPHP开发者周刊」招募志愿者
- ThinkPHP6.0日志变化
- ThinkPHP5.1.38版本发布——常规更新
- ThinkPHP6.0RC4版本发布——ORM独立,日志多通道支持
- ThinkORM2.0开发指南上线
- ThinkPHP6.0RC5版本发布——多应用模式独立,中间件机制调整
- ThinkPHP6.0版本发布——程序员节福利
- ThinkPHP5.1.39LTS版本发布——常规更新
- ThinkPHP6.0.1版本发布——圣诞快乐!
- 回顾2019,展望2020!
- ThinkPHPV6.0.2版本发布——2020新春快乐!
- 周年福利系列:Swoole合作优惠
- 亿速云成为ThinkPHPV6.0独家赞助发布商🎉
- 新冠疫情工具和限免资源专题(保持更新中)
- 周年福利系列:创宇信用认证合作优惠
- 周年福利系列:码云企业版限时10%优惠
- 周年福利系列:想天短说抵现优惠
- think-swoole直播:从零开始掌握swoole开发
- 周年福利系列:B2C开源电商ShopXO授权8折优惠
- 周年福利系列:LayuiAdmin 永久授权限时优惠
- ThinkPHP资源导航站上线——构建生态 服务未来
- ThinkPHP官方技术支持服务和应用服务市场上线公测
- ThinkPHP市场精选——推广基本要素
- ThinkPHP市场精选——客服聊天专题
- ThinkPHPV6.0.3版本发布——端午安康
- ThinkPHP开发者扶持计划
- 6.0.3版本关键更新及升级事项
- 「ThinkPHP开发者周刊」改版重启
- ThinkPHP市场精选——企业建站专题
- ThinkPHP 提供统一API接口服务
- ThinkPHP市场精选——直播电商专题
- ThinkAPI服务SDK发布
- 官方服务市场启用独立子域名
- ThinkPHP市场精选——刷脸支付专题
- ThinkAPI推出会员服务计划
- ThinkPHPV6.0.4版本发布——中秋国庆双节快乐
- ThinkPHPV5.1.40版本发布——常规更新
- 1024程序员节福利走一波
- ThinkPHP V6.0.5版本发布——兼容Composer2.0
- 知识图谱应用场景——源论技术沙龙
- ThinkPHP5.*版本改进Composer2.0的兼容
- 官方市场双十一精选推荐
- 技术人做产品有机会么(文末送课程)
- 本周秒杀——古德云售后获客营销系统
- ThinkAPI服务更新——支持接口分组和PHP版本依赖调整
- PHP8新特性盘点
- PHP8新特性系列:构造器属性提升使用及注意事项
- ThinkPHP2021新年寄语
- ThinkPHP V6.0.6&V5.1.41版本发布——兼容PHP8.0
- PHP如何更优雅地调用API接口
- ThinkPHP V6.0.7发布——修正版本
- ThinkAPI服务更新——IP白名单
- 最新版ThinkORM对于时间字段的调整
- ThinkAPI短信接口正式上线
- ThinkPHP V6.0.8版本发布——多环境变量配置支持
- 顶想云写作服务开启第一次公测
- ThinkSSL上线——官方SSL/TLS证书服务
- MDBootstrap国内用户福利——ThinkPHP官方市场首发
- ThinkPHP V6.0.9版本发布——常规更新
- ThinkORM功能盘点——虚拟模型
- 全面支持主流GIT版本库——云写作服务第二次公测
- 云写作服务私有化部署方案之:版本库私有化
- 看云双十一活动
- ThinkPHP V6.0.10LTS发布——兼容PHP8.1
- ThinkPHP V6.0.12发布——命令行兼容8.1
- 顶想云知识管理上线公测——构建企业文档中心和知识库
- 顶想云上线——助力生态数字化建设
- 618活动进行中——官方市场迎来一波更新
- 顶想云知识管理正式上线——看云文档启动迁移服务
- ThinkPHP V6.0.13发布——常规更新
- 顶想云网站助理服务上线——构建产品支持服务
- ThinkPHP发布6.1.0&6.0.14版本——安全更新
- ThinkPHP新版社区上线试运营
- ThinkAPI上架人脸核身接口——助力网站实名认证
- 辞旧迎新——旧版社区停止注册及发帖
- ThinkPHP6.1.2版本发布——兼容PHP8.2