2025年,ThinkPHP 8.0作为国内最流行的PHP框架之一,其中间件和依赖注入机制让代码更加模块化、可测试。中间件用于处理HTTP请求的前置和后置逻辑,依赖注入则让类之间的解耦变得优雅。本文通过四个实战案例,带你掌握这些核心特性。
1. 为什么需要中间件与依赖注入?
传统PHP开发中,权限验证、日志记录等横切关注点散落在各个控制器中,导致代码重复。中间件将这些逻辑集中管理,实现关注点分离。依赖注入则解决了类之间的硬编码依赖,让代码更容易测试和维护。
- 中间件:处理请求前后逻辑,如身份验证、CORS、日志
- 依赖注入:自动解析类依赖,降低耦合度
- 服务容器:管理类的创建和生命周期
2. 中间件基础:定义与注册
ThinkPHP 8.0 中间件可以在路由、控制器或全局中定义。
<?php
// 定义中间件: app/middleware/AuthCheck.php
namespace appmiddleware;
use thinkRequest;
use thinkResponse;
class AuthCheck
{
public function handle(Request $request, Closure $next): Response
{
// 前置处理:验证token
$token = $request->header('Authorization');
if (!$token || $token !== 'valid-token') {
return json(['code' => 401, 'message' => '未授权访问'], 401);
}
// 继续执行请求
$response = $next($request);
// 后置处理:添加安全头
$response->header(['X-Frame-Options' => 'DENY']);
return $response;
}
}
// 注册中间件: config/middleware.php
return [
// 全局中间件
'__global__' => [
appmiddlewareAuthCheck::class,
],
// 路由分组中间件
'user' => [
appmiddlewareLogMiddleware::class,
],
];
3. 实战案例一:路由中间件与权限控制
使用中间件实现基于角色的权限验证。
<?php
// 定义角色中间件: app/middleware/RoleMiddleware.php
namespace appmiddleware;
use thinkRequest;
use thinkResponse;
class RoleMiddleware
{
public function handle(Request $request, Closure $next, string $role = 'user'): Response
{
// 模拟从数据库获取用户角色
$userRole = $this->getUserRole($request);
// 检查角色权限
$roles = explode('|', $role);
if (!in_array($userRole, $roles)) {
return json(['code' => 403, 'message' => '权限不足'], 403);
}
return $next($request);
}
private function getUserRole(Request $request): string
{
// 从token解析角色
$token = $request->header('Authorization');
// 模拟解析
return $token === 'admin-token' ? 'admin' : 'user';
}
}
// 路由定义: route/app.php
use thinkfacadeRoute;
// 应用角色中间件到路由组
Route::group('admin', function () {
Route::get('dashboard', 'admin/Dashboard/index');
Route::get('users', 'admin/User/list');
})->middleware(appmiddlewareRoleMiddleware::class, 'admin');
// 普通用户路由
Route::group('user', function () {
Route::get('profile', 'user/Profile/index');
})->middleware(appmiddlewareRoleMiddleware::class, 'user|admin');
4. 实战案例二:依赖注入与控制反转
ThinkPHP 8.0 的依赖注入容器自动解析类的依赖关系。
<?php
// 定义服务类: app/service/UserService.php
namespace appservice;
use appmodelUser;
use thinkDbManager;
class UserService
{
private DbManager $db;
private User $userModel;
// 依赖通过构造函数注入
public function __construct(DbManager $db, User $userModel)
{
$this->db = $db;
$this->userModel = $userModel;
}
public function getUserInfo(int $id): array
{
// 使用注入的数据库实例
$user = $this->userModel->find($id);
if (!$user) {
throw new thinkexceptionHttpException(404, '用户不存在');
}
return $user->toArray();
}
public function createUser(array $data): bool
{
return $this->userModel->save($data);
}
}
// 控制器中自动注入: app/controller/UserController.php
namespace appcontroller;
use appserviceUserService;
use thinkRequest;
use thinkResponse;
class UserController
{
private UserService $userService;
// 依赖自动注入
public function __construct(UserService $userService)
{
$this->userService = $userService;
}
public function info(int $id): Response
{
try {
$user = $this->userService->getUserInfo($id);
return json(['code' => 0, 'data' => $user]);
} catch (Exception $e) {
return json(['code' => $e->getCode(), 'message' => $e->getMessage()]);
}
}
public function create(Request $request): Response
{
$data = $request->post();
$result = $this->userService->createUser($data);
return json(['code' => 0, 'message' => '创建成功']);
}
}
5. 实战案例三:服务提供者与容器绑定
使用服务提供者将接口绑定到实现,实现面向接口编程。
<?php
// 定义接口: app/contract/PaymentInterface.php
namespace appcontract;
interface PaymentInterface
{
public function pay(float $amount): bool;
public function refund(string $orderNo): bool;
}
// 实现1: 支付宝支付
namespace appservice;
use appcontractPaymentInterface;
class AlipayService implements PaymentInterface
{
public function pay(float $amount): bool
{
// 调用支付宝API
echo "支付宝支付: {$amount}元n";
return true;
}
public function refund(string $orderNo): bool
{
echo "支付宝退款: {$orderNo}n";
return true;
}
}
// 实现2: 微信支付
namespace appservice;
use appcontractPaymentInterface;
class WechatPayService implements PaymentInterface
{
public function pay(float $amount): bool
{
// 调用微信支付API
echo "微信支付: {$amount}元n";
return true;
}
public function refund(string $orderNo): bool
{
echo "微信退款: {$orderNo}n";
return true;
}
}
// 服务提供者: app/provider/PaymentServiceProvider.php
namespace appprovider;
use appcontractPaymentInterface;
use appserviceAlipayService;
use thinkService;
class PaymentServiceProvider extends Service
{
public function register(): void
{
// 绑定接口到具体实现
$this->app->bind(PaymentInterface::class, AlipayService::class);
}
public function boot(): void
{
// 启动时执行
}
}
// 在 config/app.php 注册服务提供者
'providers' => [
appproviderPaymentServiceProvider::class,
],
// 控制器中使用接口
namespace appcontroller;
use appcontractPaymentInterface;
use thinkRequest;
class PaymentController
{
private PaymentInterface $payment;
public function __construct(PaymentInterface $payment)
{
$this->payment = $payment;
}
public function pay(Request $request)
{
$amount = $request->param('amount');
$result = $this->payment->pay($amount);
return json(['code' => 0, 'message' => '支付成功']);
}
}
6. 实战案例四:中间件与依赖注入结合
在中间件中使用依赖注入,实现更强大的功能。
<?php
// 定义日志服务: app/service/LogService.php
namespace appservice;
use thinkRequest;
class LogService
{
public function log(string $message): void
{
// 写入日志文件
$logFile = runtime_path() . 'log/' . date('Y-m-d') . '.log';
$content = sprintf("[%s] %sn", date('Y-m-d H:i:s'), $message);
file_put_contents($logFile, $content, FILE_APPEND);
}
}
// 中间件中使用注入: app/middleware/LogMiddleware.php
namespace appmiddleware;
use appserviceLogService;
use thinkRequest;
use thinkResponse;
class LogMiddleware
{
private LogService $logService;
// 依赖注入
public function __construct(LogService $logService)
{
$this->logService = $logService;
}
public function handle(Request $request, Closure $next): Response
{
// 记录请求开始
$startTime = microtime(true);
$response = $next($request);
// 记录请求结束
$duration = microtime(true) - $startTime;
$message = sprintf(
'%s %s 耗时: %.4fms',
$request->method(),
$request->url(),
$duration * 1000
);
$this->logService->log($message);
return $response;
}
}
// 注册中间件
// config/middleware.php
return [
'__global__' => [
appmiddlewareLogMiddleware::class,
],
];
7. 性能对比:传统方式 vs 依赖注入
| 指标 | 传统方式 | 依赖注入方式 |
|---|---|---|
| 代码耦合度 | 高,类之间硬编码 | 低,面向接口 |
| 单元测试 | 困难,需要mock全局状态 | 容易,可以注入mock对象 |
| 扩展性 | 差,修改需要改多处 | 好,通过绑定切换实现 |
| 可读性 | 依赖关系不明确 | 构造函数明确声明依赖 |
8. 最佳实践总结
- 中间件职责单一:每个中间件只处理一个关注点(认证、日志、CORS)
- 面向接口编程:依赖注入时优先使用接口而不是具体类
- 服务提供者:使用服务提供者集中管理复杂依赖绑定
- 延迟加载:容器默认延迟加载,只在需要时实例化
- 中间件参数传递:通过
$request->withMiddleware()传递数据
// 中间件传递数据示例
class TransferMiddleware
{
public function handle(Request $request, Closure $next): Response
{
$request->withMiddleware(['user_id' => 123]);
return $next($request);
}
}
// 控制器中获取
class UserController
{
public function info(Request $request)
{
$userId = $request->middleware('user_id');
// ...
}
}
9. 总结
通过本文的案例,你掌握了ThinkPHP 8.0中间件和依赖注入的核心技术:
- 中间件的定义、注册与参数传递
- 路由中间件与权限控制
- 依赖注入容器的使用
- 服务提供者与接口绑定
- 中间件与依赖注入结合
- 最佳实践与性能对比
ThinkPHP 8.0让PHP开发更加工程化和模块化。结合中间件和依赖注入,你可以构建出高可维护性的企业级应用。现在就开始你的ThinkPHP 8.0之旅吧!
本文原创,基于ThinkPHP 8.0+。所有代码均在ThinkPHP 8.0环境中测试通过。

