在 Laravel 容器中覆盖单例
Posted
技术标签:
【中文标题】在 Laravel 容器中覆盖单例【英文标题】:Override Singleton in Laravel Container 【发布时间】:2016-03-29 03:36:15 【问题描述】:我想知道是否有一种简单的方法可以覆盖 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% 一切正常,无论我将我的服务提供者(高于或低于 ConsoleSupportServiceProvider)放在什么顺序,它仍然会在我的自定义命令上加载原始 AppNameCommand。
我已经找到了解决办法,但是如果可能的话,如果将来能了解单例服务的行为会很好吗? (如果这有什么不同的话,这是使用 Laravel 5.2。)
【问题讨论】:
【参考方案1】:我看了这个案子,似乎不是一件容易的事。如果您在自定义提供程序中使用singleton
,它将最终被默认提供程序(延迟一个)覆盖,因此似乎不是这样。
在检查了简单的方法不起作用之后,您需要做的是分析 Laravel 注册此命令时发生的情况。
因此,在您的情况下,您首先搜索command.app.name
- 您会看到它在Illuminate\Foundation\Providers\ArtisanServiceProvider
中,并且您可能希望覆盖方法registerAppNameCommand
。
所以现在您要查找 ArtisanServiceProvider
的出现以查看它的启动位置 - 您会看到它在 $providers
属性中的 Illuminate\Foundation\Providers\ConsoleSupportServiceProvider
中(您可能希望更改它)。
所以最后你应该寻找ConsoleSupportServiceProvider
的出现,你会看到它在config/app.php
中。
那么在这种情况下你需要做什么:
更改config/app.php
- 将Illuminate\Foundation\Providers\ConsoleSupportServiceProvider
更改为您的自定义ConsoleSupportServiceProvider
在您的自定义中,您应该从\Illuminate\Foundation\Providers\ConsoleSupportServiceProvider
扩展,但将$providers
从Illuminate\Foundation\Providers\ArtisanServiceProvider
更改为您的自定义ArtisanServiceProvider
最终创建自定义ArtisanServiceProvider
,它将从\Illuminate\Foundation\Providers\ArtisanServiceProvider
扩展,您使用singleton
中的自定义类覆盖registerAppNameCommand
使用这种方式,您将实现您的目标(我已经验证了自定义类将用于运行命令php artisan app:name
)。
或者,您可能希望在您的自定义 ArtisanServiceProvider
中从 $devCommands
中删除 'AppName' => 'command.app.name',
并使用您的自定义服务提供商,如您在注册单身人士时显示的那样,但我没有尝试过这种方法。
【讨论】:
是的,我认为这可以作为替代方法,并且是唯一的方法,但老实说,这是一个非常笨拙的选择,这是一种耻辱。我也可以通过解决它来覆盖命令,例如新命令将替换 app:name 如果其他人不知道 command.app.name 服务是多余的,这可能会导致潜在问题 是的,你是对的,在 Laravel 中有一些功能你需要做很多改变才能使它们工作,但在其他框架中它通常更糟:)【参考方案2】:实际上有一种更简洁的方法可以做到这一点。你基本上是想扩展一个核心绑定,这可以通过使用extend
方法来实现:
$this->app->extend('command.app.name', function ($command, $app)
return new AppNameCommand($app['composer'], $app['files']);
);
Jason Lewis 在Tutsplus 上有一篇关于 Laravel 的 IoC 的非常好的文章。一定要检查一下;)
【讨论】:
以上是关于在 Laravel 容器中覆盖单例的主要内容,如果未能解决你的问题,请参考以下文章