依赖注入 #
一、依赖注入概述 #
1.1 什么是依赖注入 #
依赖注入(Dependency Injection, DI)是一种设计模式,它将依赖关系从代码内部移到外部,由容器负责注入依赖。
text
传统方式
┌─────────────┐
│ 控制器 │
├─────────────┤
│ new Service()│ ← 硬编码依赖
└─────────────┘
依赖注入方式
┌─────────────┐ ┌─────────────┐
│ 控制器 │ │ 服务容器 │
├─────────────┤ ├─────────────┤
│ Service $service│←────│ 自动注入 │
└─────────────┘ └─────────────┘
1.2 依赖注入的好处 #
| 好处 | 说明 |
|---|---|
| 松耦合 | 组件之间依赖减少 |
| 易测试 | 可以轻松模拟依赖 |
| 易维护 | 依赖关系清晰 |
| 灵活性 | 容易替换实现 |
二、服务容器 #
2.1 什么是服务容器 #
Laravel服务容器是管理类依赖和执行依赖注入的工具。
php
// 获取服务容器实例
$container = app();
// 或使用全局辅助函数
$container = app();
2.2 绑定服务 #
php
// 简单绑定
app()->bind('service', function ($app) {
return new Service();
});
// 绑定接口到实现
app()->bind(PaymentInterface::class, StripePayment::class);
// 单例绑定
app()->singleton('service', function ($app) {
return new Service();
});
// 实例绑定
$service = new Service();
app()->instance('service', $service);
2.3 解析服务 #
php
// 解析服务
$service = app('service');
// 或使用make方法
$service = app()->make('service');
// 或使用resolve函数
$service = resolve('service');
三、构造函数注入 #
3.1 基本用法 #
php
use App\Services\UserService;
class UserController extends Controller
{
protected $userService;
public function __construct(UserService $userService)
{
$this->userService = $userService;
}
public function index()
{
$users = $this->userService->getAll();
return view('users.index', compact('users'));
}
}
3.2 多个依赖 #
php
class UserController extends Controller
{
protected $userService;
protected $mailService;
public function __construct(
UserService $userService,
MailService $mailService
) {
$this->userService = $userService;
$this->mailService = $mailService;
}
}
3.3 接口注入 #
php
// 定义接口
interface PaymentInterface
{
public function process($amount);
}
// 实现
class StripePayment implements PaymentInterface
{
public function process($amount)
{
// Stripe处理逻辑
}
}
// 绑定
app()->bind(PaymentInterface::class, StripePayment::class);
// 控制器中使用
class PaymentController extends Controller
{
protected $payment;
public function __construct(PaymentInterface $payment)
{
$this->payment = $payment;
}
public function pay($amount)
{
return $this->payment->process($amount);
}
}
四、方法注入 #
4.1 控制器方法注入 #
php
use App\Services\UserService;
use Illuminate\Http\Request;
class UserController extends Controller
{
public function store(Request $request, UserService $userService)
{
$user = $userService->create($request->validated());
return redirect()->route('users.show', $user);
}
}
4.2 路由闭包注入 #
php
use App\Services\UserService;
Route::get('/users', function (UserService $userService) {
return $userService->getAll();
});
4.3 中间件注入 #
php
use App\Services\AuthService;
class CheckRole
{
protected $authService;
public function __construct(AuthService $authService)
{
$this->authService = $authService;
}
public function handle($request, Closure $next)
{
if (!$this->authService->hasRole('admin')) {
abort(403);
}
return $next($request);
}
}
五、绑定类型 #
5.1 简单绑定 #
php
app()->bind('service', function ($app) {
return new Service();
});
// 每次解析都创建新实例
$service1 = app('service');
$service2 = app('service');
// $service1 !== $service2
5.2 单例绑定 #
php
app()->singleton('service', function ($app) {
return new Service();
});
// 只创建一次实例
$service1 = app('service');
$service2 = app('service');
// $service1 === $service2
5.3 作用域单例 #
php
app()->scoped('service', function ($app) {
return new Service();
});
// 在同一请求/生命周期内是单例
5.4 实例绑定 #
php
$service = new Service();
app()->instance('service', $service);
// 绑定已存在的实例
5.5 绑定原始值 #
php
app()->when(UserController::class)
->needs('$apiKey')
->give(config('services.api.key'));
六、上下文绑定 #
6.1 基本用法 #
php
use App\Services\PaymentInterface;
use App\Services\StripePayment;
use App\Services\PaypalPayment;
// 默认绑定
app()->bind(PaymentInterface::class, StripePayment::class);
// 上下文绑定
app()->when(AdminController::class)
->needs(PaymentInterface::class)
->give(PaypalPayment::class);
app()->when(ApiController::class)
->needs(PaymentInterface::class)
->give(StripePayment::class);
6.2 绑定闭包 #
php
app()->when(UserController::class)
->needs(PaymentInterface::class)
->give(function ($app) {
return new StripePayment(config('services.stripe.key'));
});
6.3 绑定配置值 #
php
app()->when(UserController::class)
->needs('$timeout')
->give(30);
七、服务提供者 #
7.1 创建服务提供者 #
bash
php artisan make:provider PaymentServiceProvider
7.2 注册服务 #
php
// app/Providers/PaymentServiceProvider.php
namespace App\Providers;
use Illuminate\Support\ServiceProvider;
use App\Services\PaymentInterface;
use App\Services\StripePayment;
class PaymentServiceProvider extends ServiceProvider
{
public function register()
{
$this->app->bind(PaymentInterface::class, function ($app) {
return new StripePayment(config('services.stripe.key'));
});
}
public function boot()
{
// 启动逻辑
}
}
7.3 注册服务提供者 #
php
// config/app.php
'providers' => [
// ...
App\Providers\PaymentServiceProvider::class,
],
7.4 延迟加载 #
php
class PaymentServiceProvider extends ServiceProvider implements DeferrableProvider
{
public function register()
{
$this->app->bind(PaymentInterface::class, StripePayment::class);
}
public function provides()
{
return [PaymentInterface::class];
}
}
八、自动解析 #
8.1 自动解析规则 #
Laravel会自动解析没有显式绑定的类:
php
class UserService
{
protected $repository;
public function __construct(UserRepository $repository)
{
$this->repository = $repository;
}
}
// 自动解析
$service = app(UserService::class);
8.2 解析顺序 #
text
解析流程
├── 检查是否有绑定
│ ├── 有 → 使用绑定
│ └── 无 → 自动解析
├── 检查构造函数依赖
├── 递归解析依赖
└── 创建实例
九、容器事件 #
9.1 解析事件 #
php
app()->resolving(function ($object, $app) {
// 每次解析任何对象时调用
});
app()->resolving(PaymentInterface::class, function ($payment, $app) {
// 解析特定类型时调用
});
9.2 绑定事件 #
php
app()->binding(PaymentInterface::class, function ($app) {
// 绑定时调用
});
十、标签绑定 #
10.1 定义标签 #
php
app()->bind('cache.fast', function () {
return new FastCache();
});
app()->bind('cache.slow', function () {
return new SlowCache();
});
app()->tag(['cache.fast', 'cache.slow'], 'caches');
10.2 解析标签 #
php
$caches = app()->tagged('caches');
foreach ($caches as $cache) {
$cache->flush();
}
十一、实战示例 #
11.1 支付服务 #
php
// 接口
interface PaymentInterface
{
public function charge($amount);
}
// Stripe实现
class StripePayment implements PaymentInterface
{
protected $apiKey;
public function __construct($apiKey)
{
$this->apiKey = $apiKey;
}
public function charge($amount)
{
// Stripe处理
}
}
// 服务提供者
class PaymentServiceProvider extends ServiceProvider
{
public function register()
{
$this->app->bind(PaymentInterface::class, function ($app) {
return new StripePayment(config('services.stripe.key'));
});
}
}
// 控制器
class PaymentController extends Controller
{
protected $payment;
public function __construct(PaymentInterface $payment)
{
$this->payment = $payment;
}
public function charge($amount)
{
return $this->payment->charge($amount);
}
}
11.2 通知服务 #
php
// 接口
interface NotificationInterface
{
public function send($user, $message);
}
// 邮件实现
class EmailNotification implements NotificationInterface
{
public function send($user, $message)
{
Mail::to($user->email)->send(new NotificationMail($message));
}
}
// 短信实现
class SmsNotification implements NotificationInterface
{
public function send($user, $message)
{
// 发送短信
}
}
// 上下文绑定
app()->when(UserController::class)
->needs(NotificationInterface::class)
->give(EmailNotification::class);
app()->when(AdminController::class)
->needs(NotificationInterface::class)
->give(SmsNotification::class);
11.3 仓储模式 #
php
// 接口
interface UserRepositoryInterface
{
public function find($id);
public function all();
public function create(array $data);
}
// 实现
class UserRepository implements UserRepositoryInterface
{
public function find($id)
{
return User::find($id);
}
public function all()
{
return User::all();
}
public function create(array $data)
{
return User::create($data);
}
}
// 绑定
app()->bind(UserRepositoryInterface::class, UserRepository::class);
// 服务类
class UserService
{
protected $repository;
public function __construct(UserRepositoryInterface $repository)
{
$this->repository = $repository;
}
public function getUser($id)
{
return $this->repository->find($id);
}
}
十二、最佳实践 #
12.1 依赖注入原则 #
php
// 不推荐:在类中创建依赖
class UserController extends Controller
{
public function index()
{
$service = new UserService(); // 硬编码依赖
return $service->getAll();
}
}
// 推荐:通过构造函数注入
class UserController extends Controller
{
protected $service;
public function __construct(UserService $service)
{
$this->service = $service;
}
public function index()
{
return $this->service->getAll();
}
}
12.2 使用接口 #
php
// 推荐:依赖接口而非具体实现
class PaymentController extends Controller
{
protected $payment;
public function __construct(PaymentInterface $payment)
{
$this->payment = $payment;
}
}
12.3 服务提供者组织 #
text
app/Providers/
├── AppServiceProvider.php # 应用服务
├── PaymentServiceProvider.php # 支付服务
├── NotificationServiceProvider.php # 通知服务
└── RepositoryServiceProvider.php # 仓储服务
十三、总结 #
13.1 核心要点 #
| 要点 | 说明 |
|---|---|
| 构造函数注入 | 通过构造函数注入依赖 |
| 方法注入 | 通过方法参数注入依赖 |
| 绑定 | bind、singleton、instance |
| 服务提供者 | 集中注册服务 |
| 上下文绑定 | 根据上下文注入不同实现 |
13.2 下一步 #
掌握了依赖注入后,让我们继续学习 Blade模板基础,了解Laravel强大的模板引擎!
最后更新:2026-03-28