如何在laravel中将参数传递给监听器?

how to pass parameters to listener in laravel?

我是这样注册的LogConnectionFailed

protected $listen = [
    Registered::class => [
        SendEmailVerificationNotification::class,
    ],
    'Illuminate\Http\Client\Events\ConnectionFailed' => [
        'App\Listeners\LogConnectionFailed',
    ],
];

如果没有收到对给定请求的响应,则会触发 ConnectionFailed 事件。

my class {

  public function send() {

    $response = Http::get('http://example.com');

  }

}

我需要在 LogConnectionFailed class.class.

中调用 http 客户端 class 的名称和发生这种情况的方法以及持续时间

这通过正常的参数传递是不可能的,所以我利用 PHP 原生函数 debug_backtrace() 并破解了它。

逻辑是当侦听器想要处理事件时,我们获取回调跟踪并通过调用堆栈帧进行过滤,直到找到我们的监视位置之一。

代码是这样的:

use Illuminate\Support\Str;
use Illuminate\Http\Client\Events\ConnectionFailed;

class LogConnectionFailed
{
    /**
     * Create the event listener.
     *
     * @return void
     */
    public function __construct()
    {
        //
    }

    public function handle(ConnectionFailed $event)
    {
        $backtraceCollection = Collect(debug_backtrace());
        $callerClass = $backtraceCollection->first(function($value, $key) use ($event){
            $class = $value['class'] ?? '';

            return $this->classIsWatched($class);
        });

        if ($callerClass) {
            // Store in DB or do some other stuff.
            dd([
                'class'    => $callerClass['class'],
                'function' => $callerClass['function'],
                'line'     => $callerClass['line'],
            ]);
        } else {
            dd("should skip. Not Watching classes.");
        }
    }

    private function classIsWatched(string $className): bool
    {
        return Str::is(
            ['App\Http\Controllers\*', 'App\MyClass'],
            $className
        );
    }
}

这里注意函数里面的数组classIsWatched:

['App\Http\Controllers\*', 'App\MyClass']

这些是我们要监视的 classes 或目录,这意味着如果 ConnectionFailed 由于来自这些 classes 的一些调用,它们将被捕获,否则它们将被跳过。这使您可以灵活地过滤掉并观察应用程序中的某些位置。

请注意,我们还可以使用通配符 * 来简化路径包含。例如App\Http\Controllers\Api\EventController也被观看了。

例如,如果我在 App 路径中有这个 class:

namespace App;

use Illuminate\Support\Facades\Http;

class MyClass
{
    public static function callEvent()
    {
        $response = Http::get('http://example.com');
    }
}

由于任何原因,如果 ConnectionFailed 事件调度,处理方法的输出将是:

array:3 [▼
  "class" => "App\MyClass"
  "function" => "callEvent"
  "line" => 11
]

这将为您提供 class 名称函数名称 甚至 那里引发了哪个事件。您可以简单地替换侦听器 handle 方法中的 dd() 并对数据执行您想要的操作。

关于Http Call的时长,我没有想出准确的答案,但是你可以用这个方法粗略估计一下:

dd(microtime(true) - LARAVEL_START);

handle 方法中也添加上面的代码,这给了你从应用程序启动的那一刻到你得到这个点的时间差(Http 请求失败,你进入了这个监听器) .