本文目录导读:

在 PHP 项目中,控制器的规范编写是保证代码可维护性、可测试性和团队协作效率的关键,以下是基于主流 MVC 框架(如 Laravel、ThinkPHP、Symfony、CodeIgniter 等)的通用规范化建议。
核心设计原则
- 单一职责:一个控制器方法只处理一类请求(如
create、store、show、update、destroy)。 - 瘦控制器(Skinny Controller):控制器不写业务逻辑,只负责调度(接收输入 -> 调用服务 -> 返回输出)。
- 避免重复代码:通过中间件、表单请求验证、资源控制器等机制减少模板代码。
方法命名与结构规范
RESTful 资源控制器(推荐)
使用 RESTful 风格的资源路由,标准方法:
| 动词 | URI | 方法名 | 用途 |
|---|---|---|---|
| GET | /users | index |
显示列表 |
| GET | /users/create | create |
显示创建表单 |
| POST | /users | store |
处理创建请求 |
| GET | /users/{id} | show |
显示单个资源 |
| GET | /users/{id}/edit | edit |
显示编辑表单 |
| PUT/PATCH | /users/{id} | update |
处理更新请求 |
| DELETE | /users/{id} | destroy |
删除资源 |
示例(Laravel):
class UserController extends Controller
{
public function index(Request $request): View
{
$users = UserService::list($request->validated());
return view('users.index', compact('users'));
}
public function store(UserStoreRequest $request): RedirectResponse
{
$user = UserService::create($request->validated());
return redirect()->route('users.show', $user->id)
->with('success', '用户创建成功');
}
}
自定义方法命名规范
- 动词 + 资源:
exportUsers,batchDelete,toggleStatus - 避免使用
doSomething等模糊命名
输入处理规范
使用表单请求验证
将验证逻辑从控制器分离到专门的验证类中。
// Laravel 示例
class UserStoreRequest extends FormRequest
{
public function rules(): array
{
return [
'name' => 'required|string|max:255',
'email' => 'required|email|unique:users',
'password' => 'required|min:8|confirmed',
];
}
}
// 控制器中使用
public function store(UserStoreRequest $request): JsonResponse
{
$data = $request->validated(); // 已验证过的数据
// ...
}
避免直接操作 $_GET / $_POST
始终通过框架的请求对象获取输入,便于中间件处理、单元测试和全局过滤。
不要信任用户输入
即使验证通过,在业务层也需要进一步处理(如 SQL 注入防护、XSS 过滤)。
业务逻辑分离
Service 层(推荐)
将所有业务逻辑抽取到独立的服务类中。
// 不好的做法
public function store(Request $request)
{
// 验证、数据库操作、邮件发送、日志记录全部写在这里
}
// 好的做法
public function store(UserStoreRequest $request)
{
$this->userService->createUser($request->validated());
// ...
}
Action 类(适用于复杂单一操作)
对于复杂的业务操作(如“订单结算”),可以创建单独的 Action 类。
class CheckoutAction
{
public function execute(Order $order, User $user): void
{
// 复杂的结算流程
}
}
// 控制器中调用
public function checkout(Request $request)
{
(new CheckoutAction)->execute($order, auth()->user());
}
响应输出规范
统一返回格式
- Web 视图:使用
view()或redirect(),保持视图层与控制器分离。 - API 接口:返回 JSON,包含状态码、消息、数据等。
public function show(int $id): JsonResponse { $user = UserService::find($id); return response()->json([ 'code' => 200, 'message' => 'success', 'data' => $user, ]); }
错误处理
在控制器中使用 try-catch 或通过异常处理机制统一返回错误。
public function update(int $id, Request $request): JsonResponse
{
try {
$user = UserService::update($id, $request->validated());
return $this->success($user);
} catch (NotFoundException $e) {
return $this->notFound($e->getMessage());
} catch (ValidationException $e) {
return $this->validationError($e->getErrors());
}
}
避免在控制器中直接输出 echo 或 var_dump
控制器只负责返回响应对象或视图,输出应由框架处理。
中间件与权限控制
使用中间件处理横切关注点
- 认证:
auth - 授权:
can:update,user - 限流:
throttle:60,1 - 日志:
log.requests
配置示例(Laravel)
// 在控制器构造函数中
public function __construct()
{
$this->middleware('auth');
$this->middleware('can:manage-users')->only(['store', 'update', 'destroy']);
$this->middleware('throttle:30,1')->only(['store']);
}
依赖注入
-
通过构造函数或方法参数注入依赖,避免在控制器内部硬编码。
-
存储库模式:如果需要直接操作数据库,通过依赖注入 Repository 类,而不是直接使用模型。
class UserController extends Controller { private UserService $userService; public function __construct(UserService $userService) { $this->userService = $userService; } public function index(): View { $users = $this->userService->getPaginatedList(); return view('users.index', compact('users')); } }
常见反模式(应避免)
- 上帝控制器:一个控制器包含几十个方法,处理多类资源。
- 胖控制器:控制器中包含大量 SQL 查询、业务判断、视图渲染逻辑。
- 直接操作全局变量:如
$_SESSION、$_FILES等,应通过框架封装好的对象操作。 - 返回 HTML 片段:与前端框架配合时,应使用 API 返回 JSON,而非拼接 HTML。
- 硬编码配置:如数据库连接信息、缓存时间等,应通过配置文件或环境变量管理。
实战示例(Laravel 完整资源控制器)
<?php
namespace App\Http\Controllers\Admin;
use App\Http\Controllers\Controller;
use App\Http\Requests\UserStoreRequest;
use App\Http\Requests\UserUpdateRequest;
use App\Services\UserService;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use Illuminate\View\View;
class UserController extends Controller
{
private UserService $userService;
public function __construct(UserService $userService)
{
$this->userService = $userService;
$this->middleware('auth');
$this->middleware('can:manage-users')->except(['index', 'show']);
}
public function index(Request $request): View
{
$users = $this->userService->paginate($request->all());
return view('admin.users.index', compact('users'));
}
public function store(UserStoreRequest $request): JsonResponse
{
$user = $this->userService->create($request->validated());
return response()->json([
'code' => 201,
'message' => '用户创建成功',
'data' => $user,
], 201);
}
public function show(int $id): JsonResponse
{
$user = $this->userService->findOrFail($id);
return response()->json([
'code' => 200,
'message' => 'success',
'data' => $user,
]);
}
public function update(int $id, UserUpdateRequest $request): JsonResponse
{
$user = $this->userService->update($id, $request->validated());
return response()->json([
'code' => 200,
'message' => '用户更新成功',
'data' => $user,
]);
}
public function destroy(int $id): JsonResponse
{
$this->userService->delete($id);
return response()->json([
'code' => 200,
'message' => '用户删除成功',
]);
}
}
测试可测性
- 控制器应只测试 HTTP 流程(请求、响应状态、重定向),不测试业务结果(那是 Service 层的责任)。
- 使用依赖注入使得在测试中容易模拟业务服务。
示例测试:
public function test_store_creates_user_and_redirects()
{
$this->mock(UserService::class, function ($mock) {
$mock->shouldReceive('create')->once()->andReturn(new User(['id' => 1]));
});
$response = $this->post('/users', [
'name' => 'Test',
'email' => 'test@example.com',
'password' => 'password',
]);
$response->assertRedirect(route('users.show', 1));
}
| 规范项 | 推荐做法 | 反例 |
|---|---|---|
| 方法职责 | 单一 RESTful 方法 | 一个方法处理增删改查 |
| 业务逻辑 | 委托给 Service 或 Action 类 | 直接写在控制器中 |
| 输入验证 | Form Request 类 | 在控制器中用 if 验证 |
| 响应输出 | 返回 View 或 JsonResponse 对象 |
直接 echo 或 exit |
| 依赖管理 | 构造函数或方法注入 | 静态方法或 new 实例化 |
| 错误处理 | 异常捕获 + 统一返回格式 | 使用 die() 或 var_dump() |
| 权限控制 | 中间件 | 在控制器方法中手动判断 |
遵循这些规范,你的 PHP 控制器将更加简洁、可维护、可测试,也便于团队协作和框架升级。
版权声明:NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播