Featured image of post 在 Laravel 的 bind()、singleton()、scoped()、instance() 的逻辑差异是什麽?可以在什麽样的情境下使用?

在 Laravel 的 bind()、singleton()、scoped()、instance() 的逻辑差异是什麽?可以在什麽样的情境下使用?

在 Laravel 的 bind()、singleton()、scoped()、instance() 的逻辑差异是什麽?可以在什麽样的情境下使用?

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 指令等等。

所以,在选择使用哪种绑定方法时,需要考虑到该服务在不同情境下的需求,以及是否需要共享状态或配置。

Reference

All rights reserved,未經允許不得隨意轉載
Built with Hugo
主题 StackJimmy 设计