0

在 Laravel 文档中,我看到了示例:

$this->app->when(PhotoController::class)
          ->needs(Filesystem::class)
          ->give(function () {
              return Storage::disk('local');
          });

$this->app->when([VideoController::class, UploadController::class])
          ->needs(Filesystem::class)
          ->give(function () {
              return Storage::disk('s3');
          });

https://laravel.com/docs/8.x/container#contextual-binding

我想在存储磁盘中使用不同的日志通道。

https://laravel.com/docs/8.x/logging#writing-to-specific-channels

我尝试:

    public function __construct(LoggerInterface $logger) {
        $this->logger = $logger;
    }
$this->app->when(PhotoController::class)
          ->needs('log')
          ->give(function () {
              return \Log::channel('telegram');
          });

$this->app->when([VideoController::class, UploadController::class])
          ->needs('log')
          ->give(function () {
              return \Log::channel('slack');
          });

但我得到错误:

NOTICE: PHP message: PHP Fatal error:  Uncaught Error: Maximum function nesting level of '256' reached, aborting! in /var/www/html/vendor/laravel/framework/src/Illuminate/Foundation/Application.php:792
 Stack trace:
 #0 /var/www/html/vendor/laravel/framework/src/Illuminate/Container/Container.php(646): Illuminate\Foundation\Application->resolve('Illuminate\\Log\\...')
 #1 /var/www/html/app/Providers/AppServiceProvider.php(106): Illuminate\Container\Container->get('Illuminate\\Log\\...')
 #2 /var/www/html/vendor/laravel/framework/src/Illuminate/Container/Container.php(805): App\Providers\AppServiceProvider->App\Providers\{closure}(Object(Illuminate\Foundation\Application), Array)
 #3 /var/www/html/vendor/laravel/framework/src/Illuminate/Container/Container.php(691): Illuminate\Container\Container->build(Object(Closure))
 #4 /var/www/html/vendor/laravel/framework/src/Illuminate/Foundation/Application.php(796): Illuminate\Container\Container->resolve('log', Array, true)
 #5 /var/www/html/vendor/laravel/framework/src/Illuminate/Container/Container.php(646):  in /var/www/html/vendor/laravel/framework/src/Illuminate/Foundation/Application.php on line 792

我也试过:

->needs(LoggerInterface::class)

和同样的错误。

我没有在文档中看到如何正确执行此操作的示例。没什么。

4

1 回答 1

0

旁注:您可以绑定到接口,这是一种常见用法,Laravel 称它们为“合同”,请参阅https://laravel.com/docs/8.x/container#binding-interfaces-to-implementations。所以这不是这里的问题。

关于这个问题:我不太清楚我在做什么不同,但它按我的预期工作:

use Illuminate\Support\Facades\Log;
$this->app->when(SomeController::class)->needs('log')->give(function() {
    return Log::channel('mychannel');
});

但是,'log'我不太喜欢这里的字符串。我相信它指的是记录器的所谓“外观”的名称,这给它所指的内容带来了更多的认知负担。恕我直言,最好在这里使用完整的类名,更明确地说:

use Illuminate\Log\Logger;
use Illuminate\Support\Facades\Log;
$this->app->when(SomeController::class)->needs(Logger::class)->give(function() {
    return Log::channel('mychannel');
});

然后,您可以在任何控制器中使用以下代码段:

public function __construct(Logger $logger) {
    $this->logger = $logger;
}

事实上,您有几个定义何时/需要/给予的选项:

  • Illuminate\Log\Logger::class
  • Psr\Log\LoggerInterface::class(上面的记录器实现了这个)

两者都有效,但在这两种情况下,您都需要在(要注入的)构造函数中完全按照所写的方式使用确切的类。您不能在控制器构造函数中绑定LoggerInterfaceand 类型提示Logger并期望它能够工作,它显然不能以这种方式识别继承。

另一个好消息是,显然这只适用于构造函数。控制器方法也有依赖注入,但这不能与上下文绑定结合使用。但是,它适用于此处定义的默认“简单”绑定https://laravel.com/docs/7.x/container#binding

public function showUser(Illuminate\Log\Logger $log) {
    // This typehint does not take contextual binding into account. You will receive
    // the default binding for this class.
    $log->info('...');
}

请参阅https://github.com/laravel/framework/issues/6177(tl;dr:问题已关闭,将来将不支持控制器方法的上下文绑定)。

我希望这些信息对您有所帮助。

于 2021-03-30T15:40:23.957 回答