依赖注入 #

一、依赖注入概述 #

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