【问题标题】:How to swap out dependency in laravel container如何在 laravel 容器中交换依赖项
【发布时间】:2019-10-03 23:42:44
【问题描述】:

我已经注册了一个 Paypal 服务提供商:

App\Providers\PaypalHelperServiceProvider::class,

并且,当我在控制器中输入提示时,它会正确解析:

public function refund(Request $request, PaypalHelper $paypal) {...

这是我的提供者类:

class PaypalHelperServiceProvider extends ServiceProvider
{
  protected $defer = true;

  public function register()
  {
      $this->app->bind('App\Helpers\PaypalHelper', function() {
          $test = 'test';
          return new PaypalHelper();
      });
    }

    public function provides()
    {
      $test = 'test';
      return [App\Helpers\PaypalHelper::class];
    }
  }

一切都按预期进行。现在我希望能够修改控制器以采用 PayPal 接口。然后,我将更新我的服务提供者,以有条件地传入真实类或模拟类进行测试,使用 APP_ENV 变量来确定使用哪一个。我将一些调试器放入服务提供者类中,但无法让它进入。我认为它可能只在需要时加载它们,所以我在控制器中放置了一个断点。该类确实解决了,但它仍然从未进入服务提供者类!有人可以向我解释为什么会这样吗?即使我修改了代码以传入不同的类类型,它也无法识别。

编辑:

这是我调试时看到的代码流: ControllerDispatcher -> resolveClassMethodDependencies -> resolveMethodDependencies -> transformDependency。此时我们在RouteDependencyResolveerTrait中有如下的laravel代码:

 protected function transformDependency(ReflectionParameter $parameter, $parameters, $originalParameters)
{
    $class = $parameter->getClass();

    // If the parameter has a type-hinted class, we will check to see if it is already in
    // the list of parameters. If it is we will just skip it as it is probably a model
    // binding and we do not want to mess with those; otherwise, we resolve it here.
    if ($class && ! $this->alreadyInParameters($class->name, $parameters)) {
        return $this->container->make($class->name);
    }
}

由于getClass()总是解析为接口名,所以当我们调用container->make()时,总是失败并返回

Target [App\Helpers\PaypalHelperInterface] is not instantiable.

【问题讨论】:

  • 如果您使用 $paypal = app('App\Helpers\PaypalHelper'); 获取类,则在您的控制器中这行得通吗?
  • @mrhn 不,这没有帮助。例如,即使我在帮助程序中手动设置类以返回 Exception 类,它仍然返回 PayPal 类。它似乎永远不会回到我的提供程序类中,就好像有某种类型的缓存一样。
  • provides 中的类不正确...命名空间.. 最终会是App\Providers\App\Helpers\PayPalHelper
  • @lagbox - 不,我不这么认为,我上面有这个声明use App\Helpers\PaypalHelperInterface;
  • 除非你给 App 起别名,否则它是不正确的......基本上你试图在上面的代码中解析的接口没有任何绑定,它不在提供数组中

标签: laravel containers service-provider


【解决方案1】:

改变

      $this->app->bind('App\Helpers\PaypalHelper', function() {
          $test = 'test';
          return new PaypalHelper();
      });

if (app()->environment('testing')) {
    $this->app->bind(
        PaypalHelperInterface::class,
        FakePaypalHelper::class
    )
} else {
    $this->app->bind(
        PaypalHelperInterface::class,
        PaypalHelper::class
    );
}

【讨论】:

  • 查看我对票的评论,这似乎并没有真正帮助,因为它似乎从来没有重新阅读我的提供者课程。即使我手动将响应设置为不同的类,它也会返回我原来的 PayPalHelper 类。
  • @user1015214 删除protected $defer = true;。您没有正确设置延迟。你将 Laravel 告诉 defer the provider,但永远不要告诉它何时实际引用它,因为你没有定义 Provides 方法。
  • @jfadich 我删除了它,它仍然没有进入我的提供程序类。
  • @user1015214 确保您在提供程序中设置了 use 语句或使用完全限定的命名空间。
  • 你为什么首先在服务中这样做而不是使用test mocks
【解决方案2】:

我终于找到了问题所在。我的问题是我的提供者根本没有被接走。这是解决方案

composer dumpautoload
php artisan cache:clear

https://laravel.io/forum/02-08-2015-laravel-5-service-provider-not-working

【讨论】:

    猜你喜欢
    • 2021-08-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-12-31
    • 2021-05-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多