22. 开发规范
简介
在这一节我给大家介绍一下本教程里的开发规范,这些也是笔者使用 ThinkPHP 开发项目时遵循的开发规范。本节主要介绍 ThinkPHP 开发过程中和 PHP 开发相关的规范,不涉及 前端 JavaScript 、 CSS 和资源文件规范,另外因为所介绍内容比较多篇幅较长,但希望大家耐心看完。笔者也希望这些信息可以做为大家在项目开发中的参考和借鉴。
初衷
相比 Laravel 或其它 PHP 框架而且,ThinkPHP 设计过于灵活,在团队开发过程中如果不能统一开发规范那对项目管理而言将是一种灾难!仅 ThinkPHP 官方文档里对一个功能的实现或一个属性的设置就教授给我们好几种方法。例如我们有个『CDN 域名』的变量,通过阅读官方文档里 配置 这一节,我们知道在 ThinkPHP 中有以下几种方法:
- 硬代码,直接写死。- ❌ 可维护性低
- 写死在 config/app.php 文件中。 - ❌ 无法区分环境进行配置
- 存储于 .env 文件中,使用 env() 方法直接读取。 - ❌ 虽然解决了环境变量问题但是不推荐
- 存储在 .env 和 config/app.php 文件中,然后使用 config() 函数来读取。- ✅ 最佳实践
第四种方式相比前三种方式而言,既支持环境变量,又具备极高的灵活性,假如遇到同样的 CDN 多域名随机问题,你只需要写一个助手函数,然后在 config/app.php
中调用即可,不需要动到任何一行业务逻辑代码。但当我们决定采用第四种方式时又遇到 另一个问题 —— .env
文件支持的配置类型包括 .ini
、 .xml
、 .json
、 .yaml
和 .php
,我们在开发过程中应该选择哪种配置格式?
能愿动词
为了避免歧义,本节大量使用了「能愿动词」,对应的解释如下:
- 必须(Must) - 只能这样子做,请无条件遵循,没有别的选项;
- 绝不(Must Not)- 严令禁止,在任何情况下都不能这样做;
- 应该(Should) - 强烈建议这样做,但是不强求;
- 不应该(Should Not) - 强烈建议不这样做,但是不强求;
- 可以(May) - 选择性高一点,在这个文档内,此词语使用较少。
参考: RFC 2119
规范依据
在制定开发规范时,我们依据以下信条:
- 遵循 MVC 设计模式规范;
- 遵循 ThinkPHP 官方 开发规范 ;
- 遵循 约定大于配置 原则。
目录结构
ThinkPHP 支持多模块和单模块开发(见 架构总览 ),我们创建项目时 必须 选择默认的 多模块 开发模式,此外还应遵循:
- 必须 使用默认应用目录名
application
,绝不 使用自定义应用目录名; - 模块命名 应该 遵循:用户前台模块——
index
, 系统后台模块——admin
, 共用模块——common
。
配置
- 应用配置 必须 存储在
.env
文件和config
目录中,然后使用env()
和config()
函数来读取; - 模块配置 必须 存储在模块
config
目录中,如:application/index/config
; - 配置参数名 必须 使用小写定义配置参数的规范, 如:
app_name
; - 配置文件 必须 以PHP数组格式存储;
.env
文件 必须 采用.ini
格式存储。- 必须 开启 自动时间戳 。
数据库
- 必须 遵循官方文档的数据表和字段采用小写加下划线方式命名规范;
- 绝不 使用命令行或者 PHPMyAdmin 直接创建索引或表。必须 使用 数据库迁移工具 去创建表结构,并提交版本控制器中;
- 绝不 为了共享对数据库更改就直接导出 SQL,所有修改都 必须 使用 数据库迁移工具 ,并提交版本控制器中;
- 绝不 直接向数据库手动写入伪造的测试数据。必须 使用数据填充来插入假数据,并提交版本控制器中;
- 数据库表名 必须 为「单数」, 多个单词情况下使用「Snake Case」 如:topic, user_log;
- 数据库字段名 必须 为「Snake Case」,如:
view_count
,create_time
; - 数据库表主键 必须 为「id」;
- 数据库表外键 必须 为「resource_id」,如:
user_id
,topic_id
; - 绝不 允许数据库表没有时间戳字段,每个表 必须 有创建时间(
create_time
) 和 更新时间 (update_time
),并且这两个字段 必须 是整型(int
); - 和自动时间戳字段规范保持一致,其它时间类型 必须 存储成整型(
int
) ,并且命名 应该 以_time
为后辍; - 不应该 所有数据库字段允许空值,应该 为索引、字符串或整数字段指定一个合理的默认值。(数据库允许空值(null),往往是悲剧的开始)
- 应该 为数据库表常用查询添加索引;
- 使用 数据库迁移工具 创建或更新表结构时,创建的迁移文件名 应该 清楚表达出迁移文件的用途,如创建用户表迁移文件名为
CreateTableUser
, 给用户表添加头像字段时命名为AddColumnAvatarToUser
;
验证器
验证器 是 ThinkPHP 5.1
推荐进行数据验证的方式。
- 验证器类 必须 放在模块的
validate
目录里, 如:application/common/validate
; - 验证器类名 必须 为「单数」驼峰法命名, 如:
app\common\validate\Topic
; - 类文件名 必须 遵循驼峰法命名规范, 并且 必须 与类名保持大小写一致,如
application/common/validate/Topic.php
; - 验证器类 应该 遵循 约定大于配置 方式进行命名, 数据模型
Topic
对应的验证器命名也 应该 是Topic
; - 当可以使用场景( `since' )实现对同一数据模型不用场景表单的验证时 应该 使用场景实现,不应该 再定义新的验证器;
数据模型
- 数据模型类 必须 放在模块的
model
目录里, 如:application/common/model
; - 数据模型类名 必须 为「单数」驼峰法命名, 如:
app\common\model\Topic
; - 类文件名 必须 遵循驼峰法命名规范, 并且 必须 与类名保持大小写一致,如
application/common/model/Topic.php
; - 数据模型变量 必须 为「resource_id」,如:
$user_id
,$topic_id
; - 在数据模型保存用户表单提交数据前,应该 使用 验证器 来验证表单数据是否有效;
- 当数据模型的代码臃肿时,应该 利用 Trait 来精简逻辑代码量,提高可读性;
- 绝不 「过度设计(Over Designed)」,极大降低了编码愉悦感。
控制器
- 必须 优先使用 Restful 资源控制器 ;
- 控制器类 必须 放在模块的
controller
目录里,如:application/index/controller
; - 控制器类名 必须 为「单数」驼峰法命名, 绝不 以
Controller
为后辍, 如:app\index\controller\Topic
; - 类文件名 必须 遵循驼峰法命名规范, 并且 必须 与类名保持大小写一致,如
application/index/controller/Topic.php
; - 不应该 为「方法」书写注释,这要求方法取名要足够合理,不需要过多注释;
- 应该 为一些复杂的逻辑代码块书写注释,主要介绍产品逻辑 -
为什么要这么做
; - 不应该 在控制器中书写「私有方法」,控制器里 应该 只存放「路由动作方法」;
- 绝不 遗留「死方法」,就是没有用到的方法,控制器里的所有方法,都应该被使用到,否则应该删除;
- 绝不 把业务逻辑代码写在控制器里,应该 写在对应数据模型类里;
- 绝不 在控制器里批量注释掉代码,无用的逻辑代码就必须清除掉。
路由
- 绝不 在路由配置文件里书写『闭包路由』或者其他业务逻辑代码;
- 路由器要保持干净整洁,绝不 放置除路由配置以外的其他程序逻辑;
- 必须 优先使用 Restful 路由,配合资源控制器使用;
- 应该 使用
name
方法为路由指定生成标识,路由标识 必须 优先使用『资源前缀』作为命名规范,如topic.index
的资源前缀是topic.
; - 当路由有命名时,获取 URL 时 必须 优先使用路由命名获取, 如话题详情页对应的资源路由是
topic/index
而它的路由命名是topic.index
, 那么我们应该优先使用url('[topic.index]')
获取页面路由。
助手函数
ThinkPHP 提供了很多 助手函数,但有时候我们也需要创建自己的助手函数。我们在创建自己的助手函数时应该遵循:
- 公共助手函数 必须 创建在
application/common.php
里; - 模块独有助手函数 必须 创建在模块的
common.php
里,如application/index/common.php
; - 助手函数命名 必须 遵循 ThinkPHP 官方 命名规范, 使用小写字母和下划线(小写字母开头)的方式,例如
get_client_ip
;
视图模板
- 视图模板文件 必须 放在模块的
view
目录里,如:application/index/view
; - 为了保持目录清晰,模板布局 应该 放在
view/layout
目录里; - 局部视图模板文件 必须 使用
_
前缀来命名,如:application/index/view/topic/_sidebar.html
; - 为了和 Restful 路由器和资源控制器保持一致,视图模板命名也 必须 使用资源视图的命名方式, 如控制器
app\index\controller\Topic
对应的视图模板文件存放目录是application/index/view/topic
; - 在视图模板文件里 应该 优先使用 内置标签 , 不应该 使用原生 PHP 语法。
代码版本控制
- 应该 使用 Git、SVN 或其它版本管理工具控制代码版本;
- 应该 每完成一个功能开发提交一次代码;
- 绝不 让代码在自己的电脑上过夜;
- 绝不 把本地化配置文件版本到版本控制里,应该 上传一个示例配置文件,如不要把
.env
文件纳入版本控制。 - 绝不 把项目运行缓存目录和文件纳入版本控制,如
runtime
目录里; - 绝不 把第三方扩展包纳入版本控制,如
vendor
目录里的文件和子目录; - 绝不 把用户上传文件纳入版本控制,如用户上传的话题图片和头像图片。
推荐文章: