3. 控制器:创建控制器、控制器与路由绑定、控制器中间件、资源控制器、依赖注入
控制器,说白了就是路由和业务逻辑之间的「中间人」。我刚开始学 Laravel 时,总觉得把代码全写在路由文件里也挺好,直到项目越来越大,路由文件膨胀到上千行……嗯,那场面,谁看谁头疼。
今天我们就来聊聊控制器。我会把创建、绑定、中间件、资源控制器、依赖注入这几个点,一个一个拆开讲清楚。
3.1 创建控制器
Laravel 提供了 Artisan 命令行工具,创建控制器非常方便。我个人习惯用这个命令:
php artisan make:controller UserController
执行后,会在 app/Http/Controllers 目录下生成一个 UserController.php 文件。打开看看,里面是一个空的类:
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
class UserController extends Controller
{
//
}
你可以在这里面写各种方法。比如:
public function index()
{
return view('users.index');
}
public function show($id)
{
$user = User::find($id);
return view('users.show', compact('user'));
}
php artisan make:controller UserController --resource --model=User。我经常这么干,省事。
3.2 控制器与路由绑定
控制器写好了,怎么让路由找到它?很简单,在 routes/web.php 里绑定:
use App\Http\Controllers\UserController;
Route::get('/users', [UserController::class, 'index']);
Route::get('/users/{id}', [UserController::class, 'show']);
这里 [UserController::class, 'index'] 的意思是:访问 /users 时,调用 UserController 的 index 方法。
你可能会问:为什么不用字符串写法了?比如 'UserController@index'?
嗯,Laravel 8 之后推荐用数组写法。为什么?因为 IDE 能自动识别类名,重构时也更安全。我在项目中踩过坑——字符串写法一旦改了类名,路由就静默失效,排查起来很痛苦。
3.3 控制器中间件
中间件,说白了就是请求到达控制器之前的「安检门」。比如用户登录了才能访问某些页面。
在控制器里应用中间件,有两种方式:
方式一:在路由中指定
Route::get('/users', [UserController::class, 'index'])->middleware('auth');
方式二:在控制器构造函数中指定
class UserController extends Controller
{
public function __construct()
{
$this->middleware('auth');
$this->middleware('log')->only('index');
$this->middleware('subscribed')->except('store');
}
}
我个人更推荐第二种。为什么?因为中间件的逻辑集中在控制器里,路由文件更干净。我曾经在一个大项目中,路由文件里到处是 ->middleware(),后来维护起来简直想哭。
Request 实例,要小心——此时请求还没经过中间件处理。
3.4 资源控制器
资源控制器,是 Laravel 为 CRUD 操作提供的「一键生成」方案。你想想看,一个典型的资源——比如文章、用户、产品——无非就是增删改查。Laravel 帮你把七个方法都准备好了:
| HTTP 方法 | URI | 控制器方法 | 路由名称 |
|---|---|---|---|
| GET | /posts | index() | posts.index |
| GET | /posts/create | create() | posts.create |
| POST | /posts | store() | posts.store |
| GET | /posts/{post} | show() | posts.show |
| GET | /posts/{post}/edit | edit() | posts.edit |
| PUT/PATCH | /posts/{post} | update() | posts.update |
| DELETE | /posts/{post} | destroy() | posts.destroy |
创建资源控制器:
php artisan make:controller PostController --resource
然后在路由中注册:
Route::resource('posts', PostController::class);
就这一行,上面七个路由全有了。是不是很爽?
不过我要提醒一句:资源控制器虽然方便,但别滥用。如果你的控制器里只有两三个方法,手动写路由反而更清晰。我见过有人把所有逻辑都塞进资源控制器,结果一个控制器里写了十几个方法,那就不叫「资源」了,叫「杂物间」。
3.5 依赖注入
依赖注入,是 Laravel 控制器的核心特性之一。说白了,就是 Laravel 的「服务容器」帮你自动把需要的对象「注入」到控制器方法里。
最常见的例子:
use Illuminate\Http\Request;
public function store(Request $request)
{
$name = $request->input('name');
// ...
}
这里的 Request $request 就是依赖注入。你不需要自己 new Request(),Laravel 自动帮你做了。
你还可以注入自己的服务类:
use App\Services\UserService;
public function index(UserService $userService)
{
$users = $userService->getAllUsers();
return view('users.index', compact('users'));
}
为什么这很重要?因为依赖注入让你的代码更容易测试和维护。你可以轻松替换掉 UserService 的实现,而不需要改控制器代码。
我记得有一次,项目里需要把用户服务从 MySQL 迁移到 Redis 缓存。因为用了依赖注入,我只需要改一下服务提供者里的绑定,控制器一行代码都没动。嗯,这就是依赖注入的魅力。
小结
这一章我们聊了控制器的五个核心点:
- 创建控制器:用 Artisan 命令,简单高效
- 路由绑定:用数组写法,IDE 友好
- 中间件:在构造函数里集中管理,路由更清爽
- 资源控制器:CRUD 一键生成,但别滥用
- 依赖注入:让控制器更灵活、更易测试
下一章,我们会深入 Blade 模板引擎。到时候我会分享一些我在实际项目中踩过的坑——比如模板继承的陷阱、组件的正确用法。敬请期待。
公众号:蓝海资料掘金营,微信deep3321