覆盖 Laravel 容器中的单例
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/34423170/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Override Singleton in Laravel Container
提问by Peter Fox
I'm wondering if there's a simple way to override a singleton service set in the core of the Laravel framework?
我想知道是否有一种简单的方法可以覆盖 Laravel 框架核心中的单例服务集?
e.g. I'm trying to rewrite the app:name command service '' with the following provider:
例如,我正在尝试使用以下提供程序重写 app:name 命令服务 '':
use Hexavel\Console\AppNameCommand;
use Illuminate\Console\Events\ArtisanStarting;
use Illuminate\Contracts\Events\Dispatcher;
use Illuminate\Support\ServiceProvider;
class NameCommandProvider extends ServiceProvider
{
/**
* Register any other events for your application.
*
* @param \Illuminate\Contracts\Events\Dispatcher $events
* @return void
*/
public function boot(Dispatcher $events)
{
$events->listen(ArtisanStarting::class, function ($event) {
$event->artisan->resolve('command.app.name');
}, -1);
}
/**
* Register the service provider.
*
* @return void
*/
public function register()
{
$this->app->singleton('command.app.name', function ($app) {
return new AppNameCommand($app['composer'], $app['files']);
});
}
}
I'm 100% everything is working due to extensive checks put no matter what order I put my service provider (above or below ConsoleSupportServiceProvider) it still loads the original AppNameCommand over my custom one.
我 100% 一切正常,由于进行了广泛的检查,无论我将我的服务提供商(高于或低于 ConsoleSupportServiceProvider)的顺序如何,它仍然会在我的自定义服务提供商上加载原始 AppNameCommand。
I've already got a work around BUTit would be nice to know about the behaviour of singleton services for the future if this is at all possible? (This is using Laravel 5.2 if that makes any difference.)
我已经有了一个解决办法,但是如果有可能的话,了解未来单例服务的行为会很好吗?(如果有任何区别,这是使用 Laravel 5.2。)
回答by Rémi Pelhate
There's actually a cleaner way to do this. You basically want to extend a core binding, which can be achieved by using the extend
method:
实际上有一种更清洁的方法可以做到这一点。你基本上是想扩展一个核心绑定,可以通过使用以下extend
方法来实现:
$this->app->extend('command.app.name', function ($command, $app) {
return new AppNameCommand($app['composer'], $app['files']);
});
Jason Lewishas a really nice article regarding Laravel's IoC on Tutsplus. Make sure to check it out ;)
回答by Marcin Nabia?ek
I looked at this case and it seems it not the easy one. If you use singleton
in your custom Provider it will be finally overridden by default provider (deferred one) so it seems it won't be the way.
我看了这个案子,似乎不是一件容易的事。如果您singleton
在自定义 Provider 中使用,它最终将被默认提供程序(延迟提供程序)覆盖,因此它似乎不是这样。
After checking that simple approach doesn't work, what you need to do in such case is analysing what is happening when Laravel registers this command.
在检查了那个简单的方法不起作用之后,在这种情况下你需要做的是分析 Laravel 注册这个命令时发生了什么。
So in your case you search first for command.app.name
- you see it's in Illuminate\Foundation\Providers\ArtisanServiceProvider
and there is method registerAppNameCommand
you would like to probably override.
所以在你的情况下,你首先搜索command.app.name
- 你看到它在里面Illuminate\Foundation\Providers\ArtisanServiceProvider
并且有registerAppNameCommand
你想要覆盖的方法。
So now you look for occurences of ArtisanServiceProvider
to see where it's launched - you see it's in Illuminate\Foundation\Providers\ConsoleSupportServiceProvider
in $providers
property (which you would like probably to change).
因此,现在您查找出现的情况ArtisanServiceProvider
以查看它的启动位置 - 您会看到它Illuminate\Foundation\Providers\ConsoleSupportServiceProvider
在$providers
属性中(您可能希望更改)。
So finally you should look for occurrences of ConsoleSupportServiceProvider
and you see it's in config/app.php
.
所以最后你应该寻找 的出现ConsoleSupportServiceProvider
并且你看到它在config/app.php
.
So what you need to do in this case:
那么在这种情况下你需要做的是:
- Change in
config/app.php
- changeIlluminate\Foundation\Providers\ConsoleSupportServiceProvider
into your custom oneConsoleSupportServiceProvider
- In your custom one you should extend from
\Illuminate\Foundation\Providers\ConsoleSupportServiceProvider
but change in$providers
fromIlluminate\Foundation\Providers\ArtisanServiceProvider
into your customArtisanServiceProvider
- finally create custom
ArtisanServiceProvider
which will extend from\Illuminate\Foundation\Providers\ArtisanServiceProvider
where you overrideregisterAppNameCommand
using custom class insingleton
- 改变
config/app.php
- 改变Illuminate\Foundation\Providers\ConsoleSupportServiceProvider
成你的自定义ConsoleSupportServiceProvider
- 在您的自定义一个,你应该从扩展
\Illuminate\Foundation\Providers\ConsoleSupportServiceProvider
,但改变$providers
从Illuminate\Foundation\Providers\ArtisanServiceProvider
到自定义ArtisanServiceProvider
- 最后创建自定义
ArtisanServiceProvider
,它将从\Illuminate\Foundation\Providers\ArtisanServiceProvider
您registerAppNameCommand
使用自定义类覆盖的位置扩展singleton
Using this way you will achieve your goal (I've verified it that custom class will be used running command php artisan app:name
).
使用这种方式,您将实现您的目标(我已经验证将使用自定义类运行 command php artisan app:name
)。
Alternatively you might want in your custom ArtisanServiceProvider
remove 'AppName' => 'command.app.name',
from $devCommands
and use your custom service provider as you showed where you register your singleton but I haven't tried this approach.
另外,您可能希望在您的自定义ArtisanServiceProvider
删除'AppName' => 'command.app.name',
从$devCommands
和使用您的自定义服务提供商为你呈现在您注册的单身,但我还没有尝试过这种方法。