考虑到资源的开销,这就是你为什么看到大部分绑定都是通过闭包来来实现,比如:
$this->app->singleton(RuleService::class, function () {
return new RuleService();
});
或者:
$this->app->bind(CryptTaskService::class, function () {
return config('user.mobile.is_crypt')
? new EncryptService()
: new DecryptService();
});
闭包只会在调用该服务的时候才会执行,这避免了一开始就实例化造成的开销。
当然,框架也允许你直接绑定实例来满足一些特殊需求。
宏的话我没理解楼主的意思,宏本身就是一段命名好的逻辑,你不去调用它本身也不会执行。
考虑到资源的开销,这就是你为什么看到大部分绑定都是通过闭包来来实现,比如:
$this->app->singleton(RuleService::class, function () {
return new RuleService();
});
或者:
$this->app->bind(CryptTaskService::class, function () {
return config('user.mobile.is_crypt')
? new EncryptService()
: new DecryptService();
});
闭包只会在调用该服务的时候才会执行,这避免了一开始就实例化造成的开销。
当然,框架也允许你直接绑定实例来满足一些特殊需求。
宏的话我没理解楼主的意思,宏本身就是一段命名好的逻辑,你不去调用它本身也不会执行。
看了楼上的一些评论,其实框架仅提供了服务注册的能力,并非一定要使用该能力。但想要使用服务注册,首先需要了解注册的目的。
目的一:解耦合
当你向注册对象通过字符串绑定一个闭包、类型或实例的时候,就意味着它是可替换的。举个不太恰当的例子,就好比我们如果这样替换框架提供的模型类为自己的模型:
app()->bind(Illuminate\Database\Eloquent\Model::class,YourCustomeModel::class);
而能够这样写的前提是:
- 框架本身就使用了依赖注入来提供
Illuminate\Database\Eloquent\Model::class
模型的实例化; - 你在使用模型的时候都是通过依赖注入的方式,而非直接
new
来实例化。
我们在使用三方包时的经验是,但凡是通过依赖注入(有可能不是框架提供的)进行管理的,都很容易做定制化,否则将异常困难,有的还要重复大量已经被三方包实现过的代码。
目的二:便捷
其实我们在框架中使用依赖注入的时候,完全不需要将所有要注入的服务在服务提供者中进行绑定,进需要在容器方法参数中声明即可。比如:
/**
* 工作流步骤保存事件监听器
*/
class WorkflowStepSavingListener
{
/**
* Create the event listener.
*
* @param ValidateWorkflowStepService $service 工作流步骤验证服务
*/
public function __construct(
readonly public ValidateWorkflowStepService $service
)
{
}
// ...
}
以上代码中的 ValidateWorkflowStepService
类并没有在服务提供这种注册但依然会实例化默认的同名类型,这就好办了,如果我们想在某个场景下替换它,到时候再向服务提供者中添加相应的绑定规则即可:
$this->app->bind(ValidateWorkflowStepService::class, function () {
if ('testing' === config('app.env')) {
return new YourStrictValidateService();
}
});
快速总结一下
关于依赖注入还有更多骚操作这里就不再一一展开。虽然有些跑题,但我想表达的是,项目代码随着需求的变动和演进,会保持向庞杂和混乱发展的趋势,对抗这一趋势的方法往往会在项目初期耗费一些开发学习成本和运行成本,但随着项目的展开,你可能会发现这些付出都是值得的。
推荐文章: