覆盖 Laravel 容器中的单例

我想知道是否有一种简单的方法来覆盖Laravel框架核心中的单例服务集?

例如,我正在尝试使用以下提供程序重写 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']);
        });
    }
}

我是100%一切都在工作,因为广泛的检查,无论我把我的服务提供商(高于或低于控制台支持服务提供者)的顺序,它仍然加载原始的AppNameCommand在我的自定义上。

我已经有一个解决方法,但是如果可能的话,了解未来单例服务的行为会很好吗?(这是使用Laravel 5.2,如果这有什么区别的话。


答案 1

实际上有一种更清洁的方法可以做到这一点。您基本上想要扩展核心绑定,这可以通过使用以下方法实现:extend

$this->app->extend('command.app.name', function ($command, $app) {
    return new AppNameCommand($app['composer'], $app['files']);
});

Jason LewisTutsplus上有一篇关于Laravel的IoC的非常好的文章。请务必;)


答案 2

我看了这个案例,似乎并不容易。如果在自定义提供程序中使用,它最终将被默认提供程序(延迟的提供程序)覆盖,因此似乎不会是这样。singleton

在检查了简单的方法不起作用之后,在这种情况下,您需要做的是分析当Laravel注册此命令时发生的情况。

因此,在您的情况下,您首先搜索 - 您看到它在其中,并且有一些您可能希望覆盖的方法。command.app.nameIlluminate\Foundation\Providers\ArtisanServiceProviderregisterAppNameCommand

所以现在你寻找发生的地方,看看它在哪里启动 - 你看到它在属性中(你可能想改变)。ArtisanServiceProviderIlluminate\Foundation\Providers\ConsoleSupportServiceProvider$providers

所以最后你应该寻找的出现次数,你会看到它在.ConsoleSupportServiceProviderconfig/app.php

因此,在这种情况下您需要执行的操作:

  • 更改 - 更改为自定义config/app.phpIlluminate\Foundation\Providers\ConsoleSupportServiceProviderConsoleSupportServiceProvider
  • 在你的自定义中,你应该从中扩展,但从你的自定义中改变\Illuminate\Foundation\Providers\ConsoleSupportServiceProvider$providersIlluminate\Foundation\Providers\ArtisanServiceProviderArtisanServiceProvider
  • 最后创建自定义,它将从使用自定义类覆盖的位置扩展ArtisanServiceProvider\Illuminate\Foundation\Providers\ArtisanServiceProviderregisterAppNameCommandsingleton

使用这种方式,您将实现您的目标(我已经验证了将使用自定义类运行命令)。php artisan app:name

或者,您可能希望在自定义中删除并使用自定义服务提供程序,如您显示的注册单例的位置,但我还没有尝试过此方法。ArtisanServiceProvider'AppName' => 'command.app.name',$devCommands


推荐