本文目录导读:

- 基础继承(Base Controller)
- 特征复用(Traits)
- 服务注入(Service Injection)
- 中间件/装饰器模式
- 策略模式(Strategy Pattern)
- 组合模式(Composition)
- 实战建议
在 PHP 开发中,控制器复用是一个常见的架构设计问题,合理的复用可以避免代码重复,提高可维护性,但过度复用会导致耦合和混乱,以下是几种主流的控制器复用策略,从简单到复杂:
基础继承(Base Controller)
这是最基础的复用方式,将公共逻辑放在基类中。
<?php
// BaseController.php
abstract class BaseController {
protected $request;
protected $response;
protected $logger;
public function __construct(Request $request, Response $response) {
$this->request = $request;
$this->response = $response;
$this->logger = new Logger();
}
protected function json($data, $status = 200) {
$this->response->setStatusCode($status);
$this->response->setContent(json_encode($data));
$this->response->headers->set('Content-Type', 'application/json');
return $this->response;
}
protected function validate($data, $rules) {
$validator = new Validator();
return $validator->validate($data, $rules);
}
protected function authorize($permission) {
if (!$this->user->hasPermission($permission)) {
throw new UnauthorizedException();
}
}
protected function log($message, $level = 'info') {
$this->logger->log($message, $level);
}
}
// UserController extends BaseController
class UserController extends BaseController {
public function show($id) {
$user = User::find($id);
if (!$user) {
return $this->json(['error' => 'User not found'], 404);
}
return $this->json($user);
}
}
优点: 简单、易于理解
缺点: 多人协作时容易产生“上帝基类”,继承层级过深时难以维护
特征复用(Traits)
PHP 5.4+ 支持 Traits,用于水平复用代码片段。
<?php
// JsonResponseTrait.php
trait JsonResponseTrait {
protected function jsonResponse($data, $status = 200) {
header('Content-Type: application/json');
http_response_code($status);
echo json_encode($data);
exit;
}
protected function errorResponse($message, $status = 400) {
return $this->jsonResponse([
'success' => false,
'error' => $message
], $status);
}
}
// ValidationTrait.php
trait ValidationTrait {
protected function validateRequest(array $rules) {
$validator = Validator::make($this->request->all(), $rules);
if ($validator->fails()) {
$this->errorResponse($validator->errors()->first(), 422);
}
return $validator->validated();
}
}
// AuthTrait.php
trait AuthTrait {
protected function user() {
return Auth::user();
}
protected function isAdmin() {
return $this->user() && $this->user()->role === 'admin';
}
protected function authorizeAdmin() {
if (!$this->isAdmin()) {
$this->errorResponse('Unauthorized', 403);
}
}
}
// UserController.php
class UserController {
use JsonResponseTrait, ValidationTrait, AuthTrait;
public function update($id) {
$this->authorizeAdmin();
$data = $this->validateRequest([
'name' => 'required|string|max:255',
'email' => 'required|email'
]);
$user = User::find($id);
$user->update($data);
return $this->jsonResponse(['success' => true, 'data' => $user]);
}
}
优点: 灵活、粒度细分、不强制继承关系
缺点: Traits 之间可能有冲突,需要管理它们的依赖关系
服务注入(Service Injection)
将通用业务逻辑抽到服务类中,控制器只做轻量调用。
<?php
// FileStorageService.php
class FileStorageService {
public function upload($file, $directory) {
// 处理上传逻辑
return $file->store($directory);
}
public function delete($path) {
// 删除逻辑
Storage::delete($path);
}
}
// NotificationService.php
class NotificationService {
public function send($user, $message) {
// 发送通知
}
public function notifyAdmins($message) {
foreach ($this->getAdmins() as $admin) {
$this->send($admin, $message);
}
}
}
// UserController.php
class UserController extends BaseController {
protected $fileStorage;
protected $notification;
public function __construct(
FileStorageService $fileStorage,
NotificationService $notification
) {
$this->fileStorage = $fileStorage;
$this->notification = $notification;
}
public function store() {
$user = new User();
$user->fill($this->request->all());
$user->avatar = $this->fileStorage->upload($this->request->file('avatar'), 'avatars');
$user->save();
$this->notification->send($user, 'Welcome to our platform!');
return $this->jsonResponse(['success' => true, 'data' => $user], 201);
}
}
优点: 控制器更轻量,业务逻辑可复用,便于单元测试
缺点: 需要依赖注入容器支持
中间件/装饰器模式
使用中间件处理跨控制器的横切关注点(认证、日志等)。
<?php
// TokenAuthMiddleware.php
class TokenAuthMiddleware {
public function handle($request, $next) {
$token = $request->bearerToken();
if (!$token) {
return response()->json(['error' => 'Unauthenticated'], 401);
}
$user = User::where('api_token', $token)->first();
if (!$user) {
return response()->json(['error' => 'Invalid token'], 401);
}
app()->instance('currentUser', $user);
return $next($request);
}
}
// LoggingMiddleware.php
class LoggingMiddleware {
public function handle($request, $next) {
$start = microtime(true);
$response = $next($request);
Log::info('Request completed', [
'uri' => $request->getUri(),
'duration' => microtime(true) - $start
]);
return $response;
}
}
// 配置路由中的中间件
Route::group(['middleware' => ['auth.token', 'logging']], function () {
Route::post('/api/users', 'UserController@store');
Route::put('/api/users/{id}', 'UserController@update');
});
优点: 关注点分离,可组合复用
缺点: 中间件处理请求生命周期,不适合业务逻辑复用
策略模式(Strategy Pattern)
根据不同的业务场景选择不同的处理策略。
<?php
// PaymentStrategy.php
interface PaymentStrategy {
public function processPayment($amount);
public function refund($transactionId);
}
// WeChatPayStrategy.php
class WeChatPayStrategy implements PaymentStrategy {
public function processPayment($amount) {
// 微信支付逻辑
$result = $this->wechat->createPrepayOrder($amount);
return ['type' => 'wechat', 'params' => $result];
}
public function refund($transactionId) {
// 微信退款逻辑
}
}
// AlipayStrategy.php
class AlipayStrategy implements PaymentStrategy {
public function processPayment($amount) {
// 支付宝支付逻辑
$result = $this->alipay->createPaymentUrl($amount);
return ['type' => 'alipay', 'url' => $result];
}
public function refund($transactionId) {
// 支付宝退款逻辑
}
}
// PaymentController.php
class PaymentController {
protected $strategies;
public function __construct(array $strategies) {
$this->strategies = $strategies; // ['wechat' => WeChatPayStrategy, 'alipay' => AlipayStrategy]
}
public function pay($method, $amount) {
if (!isset($this->strategies[$method])) {
return response()->json(['error' => 'Invalid payment method'], 400);
}
$strategy = $this->strategies[$method];
$result = $strategy->processPayment($amount);
return response()->json(['data' => $result]);
}
}
优点: 高扩展性,符合开闭原则
缺点: 需要良好的接口设计,适合业务分支较多的情况
组合模式(Composition)
通过对象组合而不是继承来复用功能。
<?php
// TokenAuthService.php
class TokenAuthService {
public function authenticate(Request $request) {
$token = $request->bearerToken();
return User::where('api_token', $token)->first();
}
}
// CRUDService.php
class CRUDService {
public function create($model, array $data) {
return $model::create($data);
}
public function update($model, $id, array $data) {
$instance = $model::find($id);
$instance->update($data);
return $instance;
}
public function delete($model, $id) {
return $model::destroy($id);
}
}
// UserController.php
class UserController {
private $crudService;
public $authService;
public function __construct(CRUDService $crudService, TokenAuthService $authService) {
$this->crudService = $crudService;
$this->authService = $authService;
}
public function store(Request $request) {
$user = $this->crudService->create(User::class, $request->all());
return response()->json(['data' => $user], 201);
}
public function show(Request $request) {
$user = $this->authService->authenticate($request);
// 业务逻辑...
}
}
优点: 解耦彻底,组合灵活,易于测试
缺点: 需要更多代码量,类增多
实战建议
分层复用策略
在实际项目中,建议分层组合使用:
<?php
// 1. 基础层(BaseController + Traits)
class BaseController {
use JsonResponseTrait, LoggingTrait, ValidationTrait;
protected function getUser() {
return app()->make(TokenAuthService::class)->authenticate(request());
}
}
// 2. 业务层(Service层)
class UserService {
public function register(array $data) {
DB::beginTransaction();
try {
$user = User::create($data);
$this->sendWelcomeNotification($user);
DB::commit();
return $user;
} catch (\Exception $e) {
DB::rollBack();
throw $e;
}
}
}
// 3. 控制器薄层(薄控制器)
class AuthController extends BaseController {
protected $userService;
public function __construct(UserService $userService) {
$this->userService = $userService;
}
public function register() {
$data = $this->validate(request(), [
'name' => 'required|string',
'email' => 'required|email|unique:users'
]);
try {
$user = $this->userService->register($data);
return $this->jsonResponse(['success' => true, 'data' => $user], 201);
} catch (\Exception $e) {
return $this->errorResponse($e->getMessage(), 500);
}
}
}
// 4. 接口层(中间件 + 路由)
Route::post('/register', 'AuthController@register')->middleware('throttle:10,1');
选择标准建议
| 场景 | 推荐策略 | 理由 |
|---|---|---|
| 小项目/快速开发 | 基础继承 | 简单直接 |
| 中大型项目 | Traits + Service | 平衡灵活性和维护性 |
| 横切关注点 | 中间件 | 认证、日志、限流等 |
| 业务分支多 | 策略模式 | 支付、导入导出等 |
| 高度解耦需求 | 组合模式 | 微服务和复杂业务 |
需要注意的坑
- 避免过度继承:继承层级不要超过 3 层
- Traits 管理:Traits 之间有依赖时,要用
insteadof和as解决冲突 - 控制器中不要写业务逻辑:只做参数解析和响应处理
- 依赖注入而非硬编码:使用容器管理服务实例
- 保持一致性:团队统一使用一种复用风格
推荐阅读
- Laravel 官方文档的 Service Container / Service Providers
- PHP 设计模式 - 组合 vs 继承
- 领域驱动设计(DDD)中的 Application Service 层
控制器复用没有银弹,建议遵循 “薄控制器、厚服务” 的原则,结合使用:
- BaseController:存放通用响应和工具方法
- Traits:细粒度的横切逻辑
- Service 层:核心业务逻辑
- 中间件:请求级横切关注点
- 策略模式:复杂业务分支
根据项目的规模、团队熟练度和需求变更频率来选择合适策略,并在实际开发中不断演进优化。