laravel 6服务容器通过ioc+di实现解耦:业务类依赖接口而非具体实现,绑定在appserviceprovider中配置,构造函数类型提示自动注入,配合repository模式隔离数据访问,测试时可轻松替换mock。

用接口定义契约,隔离变化
把业务逻辑需要的服务能力,抽成自定义接口,放在 app/Contracts 下。例如订单处理需要通知能力:
app/Contracts/Notifier.php
interface Notifier
{
public function send(string $to, string $message): bool;
}
这个接口不提邮件、短信、站内信——它只定义“能发通知”这件事。业务类(如 OrderService)只依赖这个接口,后续换实现完全不影响它。
绑定接口到具体实现,交给容器调度
在 AppServiceProvider@register() 中告诉容器:“当有人要 Notifier,就给 EmailNotifier”:
-
$this->app->bind(Notifier::class, EmailNotifier::class);—— 每次都新建实例 -
$this->app->singleton(Notifier::class, SmsNotifier::class);—— 全局单例(适合无状态服务) - 或用闭包动态选择:
$this->app->bind(Notifier::class, function ($app) { return config('app.env') === 'production' ? new SmsNotifier() : new LogNotifier(); });
这样,切换通知方式只需改绑定,不用动任何业务类代码。
构造函数类型提示,自动注入,零手动 new
在业务类中直接写接口类型提示,Laravel 6 容器会自动解析并注入对应实现:
app/Services/OrderService.php
class OrderService
{
public function __construct(private Notifier $notifier) {}
public function complete(int $orderId): void
{
// 业务逻辑专注“做什么”,不操心“怎么通知”
$this->notifier->send('admin@example.com', "订单 {$orderId} 已完成");
}
}
控制器、队列任务、命令行指令等任何地方使用 OrderService,都不需要 new OrderService(new EmailNotifier()),容器全程托管依赖链。
配合 Repository 模式,进一步剥离数据访问
对数据库操作也遵循同样原则:定义 ProductRepositoryInterface,绑定到 EloquentProductRepository。业务类只调用 $repo->create($data),不出现 Product::create() 或 DB 查询语句。
- 测试时可注入 Mock 实现,无需数据库
- ApiProductRepository 并改绑定
- 控制器里只留 HTTP 相关逻辑(验证、响应格式),彻底与业务和数据解耦











