当前位置:网站首页>[laravel series 7.5] event system
[laravel series 7.5] event system
2022-06-11 19:27:00 【Ma Nong Lao Zhang ZY】
The event system
Speaking of events , What do you think ?JS The callback function in , Button callback event ? you 're right , These are all applications of events . But in the Laravel in , Events are a decoupling mechanism , yes The observer A manifestation of the pattern . It allows you to subscribe to and listen to events that occur in your application . The most typical example , When you complete the order , Need to send SMS 、 Email or in app notification , We usually use the observer pattern to implement . Events , Is the encapsulation of this operation , Very convenient and easy to use .
Register events and listeners
First, we need to create events and listeners corresponding to events . You can take event As a subscriber , Then use the listener to process the subscribed content . Generally speaking , Event at app/Events Under the table of contents , and Monitor be located app/Listeners Under the table of contents . If you are newly installed Laravel Environmental Science , These two directories may not exist , Then we can manually create , You can also directly use the command line to generate the corresponding file , These directories will be created automatically .
If you create event related file classes yourself , You need to implement some fixed methods by yourself , relatively speaking , It will be more convenient to create the command line .
php artisan make:event TestEvent
php artisan make:listener TestListener --event=TestEventad locum , We use the command line make:event Create an event class , And then use make:listener Create a listener . We specified the event object for the listener to handle , That is, the parameters passed later . The contents of the generated file are as follows :
// app/Events/TestEvent.php
class TestEvent
{
use Dispatchable, InteractsWithSockets, SerializesModels;
public function __construct()
{
//
}
public function broadcastOn()
{
return new PrivateChannel('channel-name');
}
}
// app/Listeners/TestListener.php
class TestListener
{
public function __construct()
{
//
}
public function handle(TestEvent $event)
{
//
}
}Simple events and listeners are done , You can see in the listener , our handle() The parameter received by the method is a TestEvent object . Next we need to go app/Providers/EventServiceProvider.php Of listen Register this event and listener in the array variable .
protected $listen = [
TestEvent::class => [
TestListener::class
],
// …………
];such , The whole event and the listener are set .
Test call events
To invoke an event , Let's start by giving events and listeners something to do . Then we can simply output something . You can add a variable to the constructor of the event .
// app/Events/TestEvent.php
public $a = '';
public function __construct($a)
{
//
$this->a = $a;
}Then output the value of this variable in the listener .
// app/Listeners/TestListener.php
public function handle(TestEvent $event)
{
//
echo $event->a;
}Then we trigger this event in the route .
\App\Events\TestEvent::dispatch('aaa');
\Illuminate\Support\Facades\Event::dispatch(new \App\Events\TestEvent('bbb'));
event(new \App\Events\TestEvent('ccc'));Here we use three forms of triggering events . Using the event class itself dispatch() Method , Use Event Facade dispatch() Method , And the use of event() Auxiliary function . They all work the same , For event distribution . Pay attention to this dispatch keyword , It is a distribution , Instead of triggering . What is the meaning here ?
We said before , Event systems are used for decoupling , That is to say , You can have multiple listeners listen to the same event ( Just like Redis Medium Pub/Sub equally ), So if the event is triggered by the call , In fact, it is also distributed to multiple listeners for processing . Just like in observer mode The observer equally . our Subject Class can hold multiple Observer , When calling Subject Of notify() After method , Multiple observers can perform subsequent operations . If you are not familiar with observer mode , Or have forgotten what we said about the observer model , You can move PHP Observer mode of design mode https://mp.weixin.qq.com/s/SlSToMIGNBtU06BWNCwWvg Learn more about it .
Event subscribers
subscriber , What is this ? We have already seen , When invoking event distribution , Our listener will respond to the event , Then you can proceed with the subsequent processing . Generally, an event corresponds to a listener , Of course , We can also use multiple listeners to listen to the same event . So in turn , Can a listener listen to all the events ? Of course, no problem. , This is the role of event subscribers .
Event subscribers are classes that can subscribe to multiple events from the subscriber class itself , Allows you to define multiple event handlers in a single class . We need to manually create the event subscriber class , This class needs to have a subscribe() Method .
namespace App\Listeners;
use App\Events\TestEvent;
use App\Events\TestEvent2;
use App\Events\TestEvent3;
class TestSubscriber
{
public function handleTestEvent1($event){
echo 'This is TestEvent1', $event->a, "<br/>";
}
public function handleTestEvent2($event){
echo 'This is TestEvent2', "<br/>";
}
public function handleTestEvent3($event){
echo 'This is TestEvent3', "<br/>";
}
public function handleTestEventAll($event){
echo "This is AllTestEvent";
if(isset($event->a)){
echo $event->a;
}
echo "<br/>";
}
public function subscribe($events)
{
$events->listen(
[TestEvent::class, TestEvent2::class, TestEvent3::class,],
[TestSubscriber::class, 'handleTestEventAll']
);
$events->listen(
TestEvent::class,
[TestSubscriber::class, 'handleTestEvent1']
);
$events->listen(
TestEvent2::class,
[TestSubscriber::class, 'handleTestEvent2']
);
$events->listen(
TestEvent3::class,
[TestSubscriber::class, 'handleTestEvent3']
);
}
}From the command line , We created two more test event classes , Namely TestEvent2 and TestEvent3 . Then in the newly created TestSubscriber Class subscribe() Method to set their listening . adopt $events Of listen() Method , We can specify the object and method to handle these events . Be careful , We can specify multiple events to handle one event at the same time , It can also be specified individually . This event subscriber we also put on app/Listener Under the table of contents , Because the event subscriber itself is actually a big listener .
then , You need to go app/Providers/EventServiceProvider.php Add the registration of this event subscriber to the , It uses $subscribe Variable .
protected $subscribe = [
TestSubscriber::class,
];The rest is to test directly in the routing .
Route::get('event/test2', function(){
\App\Events\TestEvent::dispatch('aaa');
\App\Events\TestEvent2::dispatch();
\App\Events\TestEvent3::dispatch();
// aaaThis is AllTestEventaaa
// This is TestEvent1aaa
// This is AllTestEvent
// This is TestEvent2
// This is AllTestEvent
// This is TestEvent3
});Is the test result what you expected ? first aaa It is output by our ordinary listener above . then handleTestEventAll() Method output This is AllTestEventaaa , Then there are the event subscribers handleTestEvent1() Method output This is TestEvent1aaa . The following content is TestEvent2 and TestEvent3 Output. .
Event running process
For the running process of events , Let's start with the distribution method . By looking at the source code , You'll find that , Whether using the event class itself dispatch() Or use Event Facade dispatch() , The final execution is event() This auxiliary method , This method actually instantiates a events Alias objects . By finding the source code , We found that this method corresponds to vendor/laravel/framework/src/Illuminate/Events/Dispatcher.php class . The final call is also in this class dispatch() Method .
public function dispatch($event, $payload = [], $halt = false)
{
[$event, $payload] = $this->parseEventAndPayload(
$event, $payload
);
if ($this->shouldBroadcast($payload)) {
$this->broadcastEvent($payload[0]);
}
$responses = [];
foreach ($this->getListeners($event) as $listener) {
$response = $listener($event, $payload);
if ($halt && ! is_null($response)) {
return $response;
}
if ($response === false) {
break;
}
$responses[] = $response;
}
return $halt ? null : $responses;
}From the code of foreach() Part can be easily seen , This is traversing all Monitor Then directly call the listener instance to get response result . When calling the listener , Is to pass the event class to the listener as a parameter . So we are on the monitor handle() Method to get the event object . So how does our listener load ? Of course, when the framework starts running , adopt EventServiceProvider To provide .
stay config/app.php in ,providers Array variables are configured with App\Providers\RouteServiceProvider::class , That is, the event we configure and the service provider we subscribe to , It actually inherits vendor/laravel/framework/src/Illuminate/Foundation/Support/Providers/EventServiceProvider.php This service provider . In the parent class ,register() Method internal invocation Event Facade listen() Method , This method is still vendor/laravel/framework/src/Illuminate/Events/Dispatcher.php The method in .
public function listen($events, $listener = null)
{
if ($events instanceof Closure) {
return $this->listen($this->firstClosureParameterType($events), $events);
} elseif ($events instanceof QueuedClosure) {
return $this->listen($this->firstClosureParameterType($events->closure), $events->resolve());
} elseif ($listener instanceof QueuedClosure) {
$listener = $listener->resolve();
}
foreach ((array) $events as $event) {
if (Str::contains($event, '*')) {
$this->setupWildcardListen($event, $listener);
} else {
$this->listeners[$event][] = $this->makeListener($listener);
}
}
}In this method , Through the final makeListener() Method , Create a listener and put it on listeners Array , The listener array traversed during event distribution comes from here . stay makeListener() In the method , Finally, a closure callback function is returned .
public function makeListener($listener, $wildcard = false)
{
if (is_string($listener)) {
return $this->createClassListener($listener, $wildcard);
}
if (is_array($listener) && isset($listener[0]) && is_string($listener[0])) {
return $this->createClassListener($listener, $wildcard);
}
return function ($event, $payload) use ($listener, $wildcard) {
if ($wildcard) {
return $listener($event, $payload);
}
return $listener(...array_values($payload));
};
}
public function createClassListener($listener, $wildcard = false)
{
return function ($event, $payload) use ($listener, $wildcard) {
if ($wildcard) {
return call_user_func($this->createClassCallable($listener), $event, $payload);
}
$callable = $this->createClassCallable($listener);
return $callable(...array_values($payload));
};
}Now you should know , Why is it dispatch() Methodical foreach() in , This is how we get response Of course. .
$response = $listener($event, $payload);Keep going makeListener() Look down , Because the events and listeners we define are in string form , That is to say
TestEvent::class => [
TestListener::class
],Such a definition , So it will go is_string() In judgment createClassListener() Method , The internal return of this method is also a callback function , The actual listener creation ends here . Why? ? Because the callback method is only entered when we officially use it . Current listeners It is stored in the . Then when the event is distributed , We will come to this again createClassListener() Internal callback function , At this time, we will continue to look at the callback function , Its interior will continue to call createClassCallable() Method .
protected function createClassCallable($listener)
{
[$class, $method] = is_array($listener)
? $listener
: $this->parseClassCallable($listener);
if (! method_exists($class, $method)) {
$method = '__invoke';
}
if ($this->handlerShouldBeQueued($class)) {
return $this->createQueuedHandlerCallable($class, $method);
}
$listener = $this->container->make($class);
return $this->handlerShouldBeDispatchedAfterDatabaseTransactions($listener)
? $this->createCallbackForListenerRunningAfterCommits($listener, $method)
: [$listener, $method];
}
protected function parseClassCallable($listener)
{
return Str::parseCallback($listener, 'handle');
}see parseClassCallable() Method , We will find that there is handle The appearance of characters , adopt Str::parseCallback() This method will return an array . Now you must know $class, $method What do they represent .$class It is our listener class ,$method That's it. handle() Method . therefore , Finally, what we call is actually the... In the listener handle() Method .
The process of calling events and loading listeners is introduced here . The event system itself is very large , The source code is also more complex . You can see from the names of many methods in this object , The method names of the so-called elegant framework in this module are all so long , You can imagine the complexity of this component . The rest , You can further study and learn by yourself , It's better to use XDebug Debugging tools to debug it well !
summary
In addition to the simplest event operation we demonstrated , You can also use the event listener queue to handle events , This allows complete call decoupling , For example, send a text message after placing an order 、 Slow operations such as notification information , The queue can be processed slowly in the background . You can learn more about these contents by yourself , Of course , It's easy to use , But we haven't talked about the queue yet , Not much here , After learning about the queue, you can try the queue processing in the event by yourself .
Actually speaking of this , You can also see ,Laravel No embedded hook sub function is required in , This is because similar functions are implemented through events . On the whole , The event function is very easy to use , It is also very convenient to use . In your application, can you also consider applying it immediately !
Reference documents :
https://learnku.com/docs/laravel/8.5/events/10387
边栏推荐
- Visual slam lecture notes-10-2
- [image denoising] impulse noise image denoising based on absolute difference median filter, weighted median filter and improved weighted median filter with matlab code attached
- 2022-2023 MEM pre approval interview notice of School of management, Xi'an Jiaotong University
- [untitled]
- CMU 15-445 database course lesson 5 text version - buffer pool
- BottomSheetDialog 使用详解,设置圆角、固定高度、默认全屏等
- YOLOv3 Pytorch代码及原理分析(二):网络结构和 Loss 计算
- 5g communication test manual based on Ti am5728 + artix-7 FPGA development board (dsp+arm)
- 干货丨MapReduce的工作流程是怎样的?
- highcharts设置柱状图宽度、渐变、圆角、柱子上方数据
猜你喜欢

Today's sleep quality record is 60 points

leetcode:926. 将字符串翻转到单调递增【前缀和 + 模拟分析】

Highcharts sets the histogram width, gradient, fillet, and data above the column

2022 the latest software testing classic summarized by major manufacturers. After reading it, I'm not afraid I won't get an offer

What is the workflow of dry goods MapReduce?

cf:D. Black and White Stripe【连续k个中最少的个数 + 滑动窗口】

On the translation of rich text storage database format

Practice of tag recognition based on Huawei cloud image

WWDC22 开发者需要关注的重点内容

YOLOv3 Pytorch代码及原理分析(二):网络结构和 Loss 计算
随机推荐
PyMySQL利用游标操作数据库方法封装!!!
Today's sleep quality record is 60 points
CMU 15 - 445 cours de base de données Leçon 5 version texte - Pool tampon
Introduction to ieda bottom menu
Hospital intelligent infusion management system source code hospital source code
[solution] codeforces round 798 (Div. 2)
PIL pilot image processing [1] - installation and creation
Kubernetes binary installation (v1.20.15) (VIII) deploying network plug-ins
CMU 15-445 database course lesson 5 text version - buffer pool
"Case sharing" based on am57x+ artix-7 FPGA development board - detailed explanation of Pru Development Manual
关于富文本储存数据库格式转译问题
更换目标检测的backbone(以Faster RCNN为例)
Pyramid test principle: 8 tips for writing unit tests
collect. stream(). Use of the collect() method
Specific methods for porting WinCC flexible 2008 project to botu WinCC
leetcode:926. 将字符串翻转到单调递增【前缀和 + 模拟分析】
MongoDB 什么兴起的?应用场景有哪些?
leetcode:926. Flip the string to monotonically increasing [prefix and + analog analysis]
Merge multiple binary search trees
ASEMI的MOS管24N50参数,24N50封装,24N50尺寸