laravel控制器必须严格遵循约定:路径在app/http/controllers/下,命名空间与目录结构一致,类名以controller结尾,方法用驼峰命名;路由须用数组语法并参数名完全匹配;业务逻辑应抽离至formrequest和service类,权限检查交由中间件或formrequest,构造函数中注册中间件且声明为public。

控制器写不对,路由就找不到,访问直接 404 或 Class not found;写得太重,后期改一个逻辑要翻三四个文件。Laravel 控制器的核心不是“能跑”,而是“好改、好测、好交棒”。
控制器文件位置与命名必须严格匹配约定
Laravel 通过自动加载机制定位控制器,路径、命名空间、类名三者缺一不可。错一个,php artisan route:list 就不显示,请求必报错。
- 文件必须放在
app/Http/Controllers/下(Laravel 9+ 默认路径),子目录可以有,比如app/Http/Controllers/Admin/UserController.php - 对应命名空间必须是
App\Http\Controllers\Admin,不能漏掉Admin段;写成App\Http\Controllers会加载失败 - 类名必须以
Controller结尾,如UserController;写成User或UsersController都会导致路由调度失败 - 方法名用驼峰(
showProfile),别用下划线(show_profile)——某些 PHP 版本或严格模式下会被忽略
路由绑定控制器必须用数组语法,且参数名要完全一致
Route::get('/user/{id}', [UserController::class, 'show']) 是唯一推荐写法。字符串语法('UserController@show')在 Laravel 10+ 已被弃用,运行时抛 Deprecated: Route string syntax is deprecated。
- 路由里写了
{id},控制器方法签名就必须是show($id);写成show($userId)会触发Missing required parameter - 多个参数也一样:路由
/post/{category}/{slug}对应方法show($category, $slug),顺序和名字都得对上 - 闭包路由(
function () { ... })只适合极简调试,它绕过构造函数注入、中间件生命周期、请求验证前置等关键机制,业务一复杂就失控
控制器方法里别写验证、存储、权限判断等业务逻辑
一个 store() 方法里塞了验证规则、文件保存路径拼接、模型创建、发送通知——这不是写完能跑,是埋雷等炸。
- 验证逻辑必须抽到
FormRequest类:运行php artisan make:request StoreUserRequest,把rules()和authorize()写进去,控制器里只留store(StoreUserRequest $request) - 数据库操作、第三方服务调用、多模型协同等,全扔进
Service类(如UserService),控制器只负责调用$this->userService->create($data) - 权限检查别在方法里
if (!auth()->user()->can('...')),要么放FormRequest::authorize(),要么走中间件($this->middleware('can:update,user'))
中间件注册只能在构造函数,且不能漏掉 parent::__construct()
$this->middleware('auth') 写在 index() 方法里完全无效;写在构造函数但没声明 public function __construct(),PHP DI 容器就无法实例化该控制器。
- 中间件注册必须在构造函数中完成,且只能在这里注册
- 如果加了自定义构造函数,记得显式声明为
public;protected或private会导致容器无法调用 -
Controller基类的__construct()是空的,不需要手动调parent::__construct()—— 这个常见误解反而容易引发错误 - 中间件参数要写全:字符串
'auth'可以,类名Authenticate::class也可以,但别混用或写错命名空间
最常被跳过的其实是命名空间同步和参数名一致性——这两处出错不会报语法异常,而是静默 404 或参数缺失,查起来特别费时间。











