覆盖 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

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-14 12:52:04  来源:igfitidea点击:

Override Singleton in Laravel Container

phplaravellaravel-5artisanlaravel-5.2

提问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 extendmethod:

实际上有一种更清洁的方法可以做到这一点。你基本上是想扩展一个核心绑定,可以通过使用以下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 ;)

杰森·刘易斯有关于Laravel对国际奥委会非常好的文章Tutsplus。一定要检查一下 ;)

回答by Marcin Nabia?ek

I looked at this case and it seems it not the easy one. If you use singletonin 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\ArtisanServiceProviderand there is method registerAppNameCommandyou would like to probably override.

所以在你的情况下,你首先搜索command.app.name- 你看到它在里面Illuminate\Foundation\Providers\ArtisanServiceProvider并且有registerAppNameCommand你想要覆盖的方法。

So now you look for occurences of ArtisanServiceProviderto see where it's launched - you see it's in Illuminate\Foundation\Providers\ConsoleSupportServiceProviderin $providersproperty (which you would like probably to change).

因此,现在您查找出现的情况ArtisanServiceProvider以查看它的启动位置 - 您会看到它Illuminate\Foundation\Providers\ConsoleSupportServiceProvider$providers属性中(您可能希望更改)。

So finally you should look for occurrences of ConsoleSupportServiceProviderand 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- change Illuminate\Foundation\Providers\ConsoleSupportServiceProviderinto your custom one ConsoleSupportServiceProvider
  • In your custom one you should extend from \Illuminate\Foundation\Providers\ConsoleSupportServiceProviderbut change in $providersfrom Illuminate\Foundation\Providers\ArtisanServiceProviderinto your custom ArtisanServiceProvider
  • finally create custom ArtisanServiceProviderwhich will extend from \Illuminate\Foundation\Providers\ArtisanServiceProviderwhere you override registerAppNameCommandusing custom class in singleton
  • 改变config/app.php- 改变Illuminate\Foundation\Providers\ConsoleSupportServiceProvider成你的自定义ConsoleSupportServiceProvider
  • 在您的自定义一个,你应该从扩展\Illuminate\Foundation\Providers\ConsoleSupportServiceProvider,但改变$providersIlluminate\Foundation\Providers\ArtisanServiceProvider到自定义ArtisanServiceProvider
  • 最后创建自定义ArtisanServiceProvider,它将从\Illuminate\Foundation\Providers\ArtisanServiceProviderregisterAppNameCommand使用自定义类覆盖的位置扩展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 ArtisanServiceProviderremove 'AppName' => 'command.app.name',from $devCommandsand 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和使用您的自定义服务提供商为你呈现在您注册的单身,但我还没有尝试过这种方法。