## 代码规范

本篇规范制定了代码风格的相关标准，以确保团队开发时代码间具有较高程度的技术互通性。


### 定义
- `大驼峰`: 首字母大写的驼峰式 StudlyCase 
- `小驼峰`: 首字母小写的驼峰式 camelCase
- `蛇形`: 下划线链接的小写 snake_case
- `链式`: 短线链接的小写 kebab-case
- `常数式`: 全部大写字母 CONSTENT_CAST
- `标题式`: 每个单词首字母大写 Title Case
- `点式`: 英文.分割 dot.cast
- `分式`: 英文:分割 semicolon:cast

### 能愿动词

- `必须 (MUST)`：绝对，严格遵循，请照做，无条件遵守
- `一定不可 (MUST NOT)`：禁令，严令禁止
- `应该 (SHOULD)` ：强烈建议这样做，但是不强求
- `不该 (SHOULD NOT)`：强烈不建议这样做，但是不强求
- `可以 (MAY)` 和 `可选 (OPTIONAL)` ：选择性高一点，在这个文档内，此词语使用较少

### 文件夹及文件

- 存放类的文件夹 `应该` 以 `大驼峰` 的方式命名
- 资源文件夹 `应该` 以 `蛇形` 的方式命名
- 类的文件命名 `必须` 以 `大驼峰`的方式命名，并且文件名和类名一致
- 其他的php文件命名 `必须` 以 `蛇形` 的方式命名

### 基础规范
- 每个类 `应该` 都独立为一个文件，且命名空间 `必须` 符合目录层级
- 类的命名 `必须` 遵循 `大驼峰` 命名规范
- 类的常量 `必须` 遵循 `常数式` 命名规范
- 类的属性 `应该` 遵循 `小驼峰` 命名规范，私有属性 `应该` 使用'_'开始
- 类的方法 `必须` 遵循 `小驼峰` 命名规范
- 全局函数 `必须` 遵循 `蛇形` 命名规范
- 变量的命名 `应该` 遵循 `小驼峰` 命名规范

### 单数 or 复数？

#### Route
资源路由路由 URI 必须 使用复数形式，如：

- `/photos/create`
- `/photos/{photo}`

错误的例子如：
- `/photo/create`
- `/photo/{photo}`

#### Model
- 数据模型类名 `必须` 为「单数」, 如：`App\Models\Photo`
- 类文件名 `必须` 为「单数」，如：`app/Models/Photo.php`
- 数据库表名字 `必须` 为「复数」，多个单词情况下使用「Snake Case」 如：`photos`, `my_photos`
- 数据库表迁移名字 `必须` 为「复数」，如：`2014_08_08_234417_create_photos_table.php`
- 数据填充文件名 `必须` 为「复数」，如：`PhotosTableSeeder.php`
- 数据库字段名 `必须` 为「Snake Case」，如：`view_count`, `is_vip`
- 数据库表主键 `必须` 为「id」
- 数据库表外键 `必须` 为「resource_id」，如：`user_id`, `post_id`
- 数据模型变量 `必须` 为「resource_id」，如：`$user_id`, `$post_id`

#### Controller
资源控制器 `必须` 使用资源的单数形式，如：

- 类名：`PhotoController`
- 文件名：`PhotoController.php`

错误的例子如：

- 类名：`PhotosController`
- 文件名：`PhotosController.php`

#### Service
服务层 `必须` 使用资源的单数形式，如：

- 类名：`PhotoService`
- 文件名：`PhotoService.php`

错误的例子如：

- 类名：`PhotosService`
- 文件名：`PhotosService.php`

#### Repository
仓库层 `必须` 使用资源的单数形式，如：

- 类名：`PhotoRepository`
- 文件名：`PhotoRepository.php`

错误的例子如：

- 类名：`PhotosRepository`
- 文件名：`PhotosRepository.php`

### API接口规范

#### 路由

- 所有API接口 `必须` 通过路由文件下的 `api.php` 进行定义，其他接口如文件上传、第三方授权登录 `必须` 通过路由文件下 `web.php` 进行定义
- 所有路由的前缀 `必须` 以 `Service` 的 `链式` 方式定义
- 所有路由 `必须` 同时兼容 `GET` 和 `POST` 两种请求方式

#### 数据处理

> 对于API当中的正确和异常的处理，各家公司的方式各有不同。有的将所有返回的HTTP状态码均设为200，错误在json中以全局错误码设定；也有将HTTP状态码作为错误的判断标准。
> 
> 综合考虑前后端分离的开发方式，以及PHP代码的可读性。本项目采用以HTTP状态码定义请求状态。

返回数据 `必须` 遵循以下规范:

```
{
    "code" => 0,
    "message" => "正确",
    "data" => $data
}
```

- code: 0表示请求成功, 其他均为错误，错误码可自定义
- message: 请求提示
- data: 返回的数据结果

> 对于请求是否成功，以是否是预期的返回来进行判断。如遇 参数不合法、未找到数据、未登录等都 `必须` 使用错误的放回形式

所有请求都应该响应HTTP响应码，请仔细阅读以下HTTP状态码含义,或与传统HTTP状态码含义有所不同：

200: 请求成功，前端需要提示 message 信息
201: 请求成功，前端不需要提示 message 信息
202: 请求失败，前端不需要提示错误 message 信息
400及以上的状态码均表示请求失败，且前端需要提示错误 message 信息

以下HTTP状态码均需要前端提示出，错误信息可自定义
- 400： (错误请求) 请求失败,请稍后重试
- 401： (未授权) 用户未登录
- 402： (需要付费) 该资源需要付费获取
- 403： (禁止) 用户没有权限
- 404： (未找到) 未找到数据
- 405： (方法禁用) 请求方法不允许
- 406： (不接受) 服务器返回的数据错误
- 407： (需要代理授权) 授权方没有权限
- 408： (请求超时) 请求其他API接口超时
- 409： (冲突) 请求太快，请休息一下 | 遇到加锁等
- 410： (已删除) 请求的数据已删除
- 411： (参数长度错误) 请求的字段过长 
- 412： (未满足前提条件) 请先进行XX操作
- 413： (请求实体过大) 上次的文件过大
- 414： (请求的 URI 过长) 请求的 URI(通常为网址)过长，服务器无法处理。
- 415： (不支持的媒体类型) 文件格式不正确
- 416： (搜索条件有误) 搜索条件有误，如时间不正确等
- 417： (未满足期望值) 请求头部不正确
- 418： (彩蛋) 虽然出错了，但获取到了彩蛋
- 421： (备用)
- 422： (备用)
- 423： (备用)
- 424： (备用)
- 425： (备用)
- 426： (备用)
- 428： (备用)
- 429： (备用)
- 431： (备用)
- 451： (法律不允许) 该访问因法律的要求而被拒绝
- 500+ 500以上错误为服务器错误，将由框架统一输出

可使用全局辅助函数进行正确输出处理：
```
return res($data = null, $message = '', $status = 200, $headers = [], $options = 256)
```

可使用全局辅助函数进行错误输出处理：
```
// 其实不要return也是可以的，但是建议加上表示程序中断
return err($message = null, $code = -1, $data = null, $statusCode = null, $headers = [], $options = 0)
```

### 其他规范
- 数据库字段名 `必须` 遵循 `蛇形` 命名规范
- 缓存的键名 `必须` 遵循 `分式` 命名规范
- Redis的键名 `必须` 遵循 `分式` 命名规范


> 附: 辅助转换全局函数

```
// 转为大驼峰
studly_case($string);  

// 转为小驼峰
camel_case($string);  

// 转为蛇形
snake_case($string);  

// 转为链式
kebab_case($string);  

// 转为常数式
constent_cast($string);  

// 转为标题式
title_case($string);  

// 转为点式
dot_cast($string);  

// 转为分式
semicolon_cast($string);  
```