Laravel 服务容器中物件绑定方法比较
方法 | bind() |
singleton() |
scoped() |
instance() |
---|---|---|---|---|
描述 | 每次解析时创建一个新的实例。 | 只创建一个实例,并在后续请求中返回同一实例。 | 在每个请求/作业生命周期内只创建一个实例,请求结束后会被清除。 | 将已存在的实例绑定到容器,每次解析时返回该实例。 |
优点 | - 每次请求都是全新实例,无状态共享问题 - 记忆体使用乾淨 - 适合处理需要独立状态的逻辑 - 可为每个请求提供独特配置 |
- 节省系统资源,只需创建一次实例 - 确保状态一致性 - 适合共享配置和资源 - 高併发情况下性能较好 |
- 平衡了记忆体使用和状态共享 - 请求内状态共享但请求间隔离 - 适合Web请求场景 |
- 完全控制实例建立时机 - 可预先配置实例状态 - 适合需要特定配置的服务 |
缺点 | - 需较多系统资源重複创建实例 - 高併发下可能影响性能 - 不适合需要共享状态的场景 - 可能导致性能问题,因为每次都要创建新实例。 |
- 共享状态可能导致难追踪的bug - 不适合需要独立状态的场景 - 记忆体佔用持续到程式结束 - 测试需特别注意状态重置 - 如果该实例持有状态,可能会导致意外行为。 |
- 可能在长时间执行的任务中出现问题 - 需要理解请求生命週期 - 不适合CLI命令 |
- 较不灵活 - 无法动态调整实例配置 - 可能佔用启动时的记忆体 - 不适合需要延迟加载或多个实例的情况。 |
使用情境 | 用于短期使用的服务或需要独立状态的类别。 | 用于全局共享服务,如日誌记录器或配置管理器。 | 用于需要在请求中保持状态但不希望跨请求的服务,如资料库连接。 | 当你已经有一个实例并希望重複使用时,如共享配置对象。 |
范例 | 当你有一个 Product 类别,每次请求不同产品资料时,你希望每次都建立新的 Product 实例。 |
当你有一个 Logger 类别,你希望所有日誌写入操作都使用同一个实例来保持一致性。 |
当你有一个 ShoppingCart 类别,在同一个请求中需要共享购物车状态。 |
当你有一个 DatabaseConfig 类别,需要在应用启动时就设定好连接参数。 |
范例
使用 bind()
$this->app->bind('Product', function () {
return new Product();
});
每次调用 app('Product')
都会返回一个新的 Product
实例。
使用 singleton()
$this->app->singleton('Logger', function () {
return new Logger();
});
每次调用 app('Logger')
都会返回相同的 Logger
实例。
使用 scoped()
$this->app->scoped(Transistor::class, function (Application $app) {
return new Transistor($app->make(PodcastParser::class));
});
在同一个请求生命週期内共享同一个实例,不同请求会建立新实例。
使用 instance()
$service = new Transistor(new PodcastParser);
$this->app->instance(Transistor::class, $service);
直接绑定一个已存在的实例到容器。
总结
Laravel 目前可以应用在很多不同类型的情境,像是 Web 请求、CLI 命令、Queue 工作、Console 指令等等。
所以,在选择使用哪种绑定方法时,需要考虑到该服务在不同情境下的需求,以及是否需要共享状态或配置。