我们了解Laravel的事件模式,需要先了解观察者模式
观察者模式的详细介绍 www.jianshu.com/p/4be5de46e…
观察者模式介绍
当对象间存在一对多关系时,则使用观察者模式(Observer Pattern)。比如,当一个对象被修改时,则会自动通知它的依赖对象。观察者模式属于行为型模式。
观察者模式实现
观察者模式使用三个类 Subject、Observer 和 Client。Subject 对象带有绑定观察者到 Client 对象和从 Client 对象解绑观察者的方法。我们创建 Subject 类、Observer 抽象类和扩展了抽象类 Observer 的实体类。
观察者的代码实现
class Subject
{
private $subject = [];
public function notify()
{
$this->notifyAllObservers();
}
public function attach(Observer $observer)
{
array_push($this->subject,$observer);
}
public function notifyAllObservers()
{
foreach ($this->subject as $v) {
$v->update();
}
}
}
abstract class Observer
{
protected $subject;
public abstract function update();
}
class BinaryObserver extends Observer
{
public $subject;
public function __construct(Subject $subject)
{
$this->subject = $subject;
$this->subject->attach($this);
}
public function update()
{
echo "BinaryObserver update".PHP_EOL;
}
}
class HexaObserver extends Observer
{
public $subject;
public function __construct(Subject $subject)
{
$this->subject = $subject;
$this->subject->attach($this);
}
public function update()
{
echo "HexaObserver update".PHP_EOL;
}
}
//测试
$subject = new Subject();
new BinaryObserver($subject);
new HexaObserver($subject);
$subject->notify();
有了上面的观察者模式的基础之后,我们使用一个简单的方式来模拟实现Laravel的事件机制
class Params
{
public static $listens = []; //保存已经实例化的对象
}
$listen = [
"RegisterEvent" => [
"LoggerListen",
"RecordListen",
]
];
//循环这个数组
foreach ($listen as $event => $listeners) {
foreach ($listeners as $listener) {
event($event, $listener);
}
}
fire(new RegisterEvent("xioabai", "15"));
/**
* 绑定事件
* @param $event
* @param $listener
*/
function event($event, $listener)
{
Params::$listens[$event][] = make($listener);
}
/**
* 使用反射来获取到类
* @param $listen
*/
function make($listen)
{
$ref = new \ReflectionClass($listen);
$bool = $ref->getMethod("handler");
if (empty($bool)) {
throw new Exception("不存在handler方法");
}
return $ref->newInstance();
}
//事件启动
function fire($eventLogic)
{
//如果是个类 获取类名
if (is_object($eventLogic)) {
$listStr = get_class($eventLogic);
} else {
if (is_string($eventLogic)) {
$listStr = $eventLogic; //如果是字符串的话 需要实例化
}
}
foreach (Params::$listens[$listStr] as $event => $listen) {
call_user_func_array([$listen, "handler"], [$eventLogic]);
}
}
//事件类
class RegisterEvent
{
public $name;
public $age;
public function __construct($name, $age)
{
$this->name = $name;
$this->age = $age;
}
}
//监听
class LoggerListen
{
public function __construct()
{
}
public function handler(RegisterEvent $event)
{
echo "LoggerListen" . $event->age;
echo "LoggerListen" . $event->name;
}
}
//监听
class RecordListen
{
public function __construct()
{
}
public function handler(RegisterEvent $event)
{
echo "RecordListen" . $event->age;
echo "RecordListen" . $event->name;
}
}
上面的代码跟Laravel的代码实现已经很接近了,接下来我们粗略的看看Laravel事件的实现大致代码
//Providers/EventServiceProvider.php
class EventServiceProvider extends ServiceProvider
{
/**
* The event listener mappings for the application.
*
* @var array
*/
protected $listen = [
'App\Events\Event' => [
'App\Listeners\EventListener',
],
];
/**
* Register any events for your application.
*
* @return void
*/
//在前面我们知道服务提供者register之后会调用boot,我们去看他的父类的实现方法
public function boot()
{
parent::boot();
}
}
//Illuminate/Foundation/Support/Providers/EventServiceProvider.php
public function boot()
{
//子类定义的$listen
foreach ($this->listens() as $event => $listeners) {
foreach ($listeners as $listener) {
//调用Listen方法
Event::listen($event, $listener);
}
}
foreach ($this->subscribe as $subscriber) {
Event::subscribe($subscriber);
}
}
//Illuminate/Events/Dispatcher.php
public function listen($events, $listener)
{
foreach ((array) $events as $event) {
if (Str::contains($event, '*')) {
$this->setupWildcardListen($event, $listener);
} else {
//进行创建,并且绑定
$this->listeners[$event][] = $this->makeListener($listener);
}
}
}
//Illuminate/Events/Dispatcher.php
public function makeListener($listener, $wildcard = false)
{
//如果是字符串的话
if (is_string($listener)) {
//进行创建
return $this->createClassListener($listener, $wildcard);
}
return function ($event, $payload) use ($listener, $wildcard) {
if ($wildcard) {
return $listener($event, $payload);
}
return $listener(...array_values($payload));
};
}
//Illuminate/Events/Dispatcher.php
public function createClassListener($listener, $wildcard = false)
{
//返回回调函数
return function ($event, $payload) use ($listener, $wildcard) {
if ($wildcard) {
return call_user_func($this->createClassCallable($listener), $event, $payload);
}
return call_user_func_array(
$this->createClassCallable($listener), $payload
);
};
}
//Illuminate/Events/Dispatcher.php
protected function createClassCallable($listener)
{
list($class, $method) = $this->parseClassCallable($listener);
if ($this->handlerShouldBeQueued($class)) {
return $this->createQueuedHandlerCallable($class, $method);
}
return [$this->container->make($class), $method];
}
//Illuminate/Events/Dispatcher.php
//调用回调函数的handle方法
protected function parseClassCallable($listener)
{
return Str::parseCallback($listener, 'handle');
}
//Illuminate/Events/Dispatcher.php
protected function createClassCallable($listener)
{
list($class, $method) = $this->parseClassCallable($listener);
//如果继承了ShouldQueue 事件就走队列
if ($this->handlerShouldBeQueued($class)) {
return $this->createQueuedHandlerCallable($class, $method);
}
//make 获取对下对类的实力
return [$this->container->make($class), $method];
}
以上大致分为三个步骤
- Laravel拿到我们定义的数组
protected $listen = [
'App\Events\Event' => [
'App\Listeners\EventListener',
],
];
- 对这个数组进行Make获取到实例化的对象,返回回调函数,并且回调函数里面执行handle方法
- 将根据事件和监听器对应的关系保存在
event][]数组
以上就是事件的注册,接下来我们看看Laravel是怎么调用这些事件的
//Laravel事件的调用
Event::fire(new Observer()); //调用事件,传递我们的事件对象
//Illuminate\Events\Dispatcher.php
public function fire($event, $payload = [], $halt = false)
{
return $this->dispatch($event, $payload, $halt);
}
//Illuminate\Events\Dispatcher.php
public function dispatch($event, $payload = [], $halt = false)
{
// When the given "event" is actually an object we will assume it is an event
// object and use the class as the event name and this event itself as the
// payload to the handler, which makes object based events quite simple.
list($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 a response is returned from the listener and event halting is enabled
// we will just return this response, and not call the rest of the event
// listeners. Otherwise we will add the response on the response list.
//如果传递了halt参数,则不会再调用其他事件了,直接返回
if ($halt && ! is_null($response)) {
return $response;
}
// If a boolean false is returned from a listener, we will stop propagating
// the event to any further listeners down in the chain, else we keep on
// looping through the listeners and firing every one in our sequence.
//如果返回的false将不再调用
if ($response === false) {
break;
}
$responses[] = $response;
}
return $halt ? null : $responses;
}
可以看出事件的执行,其实就是执行上面创建的数组的回调函数,至此Laravel事件的分析就到此为止