admin 管理员组

文章数量: 886993

event php,php

Event manager

简洁,功能完善的事件管理实现

实现自 Psr 14 - 事件管理器

支持设置事件优先级

支持快速的事件组注册

支持通配符事件的监听

项目地址

安装

composer 命令

composer require inhere/event

composer.json

{

"require":{

"inhere/event":"dev-master"

}

}

直接拉取

git clone .git

事件管理器

事件管理器, 也可称之为事件调度器。 事件的注册、调度(触发)都是由它管理的。

use Inhere\Event\EventManager;

$em = new EventManager();

事件监听器

监听器允许是:

function 函数

一个闭包

一个监听器类(可以有多种方式)

1. function

// ...

$em->attach(Mailer::EVENT_MESSAGE_SENT, 'my_function');

2. 闭包

// ...

$em->attach(Mailer::EVENT_MESSAGE_SENT, function(Event $event) {

// $message = $event->message;

// ... some logic

});

3. 监听器类(有多种方式)

类里面存在跟事件相同名称的方法

此种方式可以在类里面写多个事件的处理方法

class ExamListener1

{

public function messageSent(EventInterface $event)

{

echo "handle the event{$event->getName()}\n";

}

}

一个类(含有 __invoke 方法)

此时这个类对象就相当于一个闭包

class ExamListener2

{

public function __invoke(EventInterface $event)

{

echo "handle the event{$event->getName()}\n";

}

}

实现接口 EventHandlerInterface

触发时会自动调用 handle() 方法。

class ExamHandler implements EventHandlerInterface

{

/**

* @param EventInterface $event

* @return mixed

*/

public function handle(EventInterface $event)

{

// TODO: Implement handle() method.

}

}

实现接口 EventSubscriberInterface

可以在一个类里面自定义监听多个事件

/**

* Class EnumGroupListener

* @package Inhere\Event\Examples

*/

class EnumGroupListener implements EventSubscriberInterface

{

const TEST_EVENT = 'test';

const POST_EVENT = 'post';

/**

* 配置事件与对应的处理方法

* @return array

*/

public static function getSubscribedEvents(): array

{

return [

self::TEST_EVENT => 'onTest',

self::POST_EVENT => ['onPost', ListenerPriority::LOW], // 还可以配置优先级

];

}

public function onTest(EventInterface $event)

{

$pos = __METHOD__;

echo "handle the event{$event->getName()}on the:$pos\n";

}

public function onPost(EventInterface $event)

{

$pos = __METHOD__;

echo "handle the event{$event->getName()}on the:$pos\n";

}

}

快速使用

1. 绑定事件触发

// a pre-defined event

class MessageEvent extends Event

{

// append property ...

public $message;

}

// in the business

class Mailer

{

use EventManagerAwareTrait;

const EVENT_MESSAGE_SENT = 'messageSent';

public function send($message)

{

// ...发送 $message 的逻辑...

$event = new MessageEvent(self::EVENT_MESSAGE_SENT);

$event->message = $message;

// 事件触发

$this->eventManager->trigger($event);

}

}

2. 触发事件

$em = new EventManager();

// 绑定事件

$em->attach(Mailer::EVENT_MESSAGE_SENT, 'exam_handler');

$em->attach(Mailer::EVENT_MESSAGE_SENT, function (EventInterface $event)

{

$pos = __METHOD__;

echo "handle the event{$event->getName()}on the:$pos\n";

});

// 这里给它设置了更高的优先级

$em->attach(Mailer::EVENT_MESSAGE_SENT, new ExamListener1(), 10);

$em->attach(Mailer::EVENT_MESSAGE_SENT, new ExamListener2());

$em->attach(Mailer::EVENT_MESSAGE_SENT, new ExamHandler());

$mailer = new Mailer();

$mailer->setEventManager($em);

// 执行,将会触发事件

$mailer->send('hello, world!');

3. 运行示例

完整的实例代码在 examples/demo.php 中。

运行: php examples/demo.php

输出:

$ php examples/exam.php

handle the event 'messageSent' on the: ExamListener1::messageSent // 更高优先级的先调用

handle the event 'messageSent' on the: exam_handler

handle the event 'messageSent' on the: {closure}

handle the event 'messageSent' on the: ExamListener2::__invoke

handle the event 'messageSent' on the: Inhere\Event\Examples\ExamHandler::handle

一组事件的监听器

除了一些特殊的事件外,在一个应用中,大多数事件是有关联的,此时我们就可以对事件进行分组,方便识别和管理使用。

事件分组 推荐将相关的事件,在名称设计上进行分组

例如:

// 模型相关:

model.insert

model.update

model.delete

// DB相关:

db.connect

db.disconnect

db.query

// 应用相关:

app.start

app.run

app.stop

1. 一个简单的示例应用类

/**

* Class App

* @package Inhere\Event\Examples

*/

class App

{

use EventManagerAwareTrait;

const ON_START = 'app.start';

const ON_STOP = 'app.stop';

const ON_BEFORE_REQUEST = 'app.beforeRequest';

const ON_AFTER_REQUEST = 'app.afterRequest';

public function __construct(EventManager $em)

{

$this->setEventManager($em);

$this->eventManager->trigger(new Event(self::ON_START, [

'key' => 'val'

]));

}

public function run()

{

$sleep = 0;

$this->eventManager->trigger(self::ON_BEFORE_REQUEST);

echo 'request handling ';

while ($sleep <= 3) {

$sleep++;

echo '.';

sleep(1);

}

echo "\n";

$this->eventManager->trigger(self::ON_AFTER_REQUEST);

}

public function __destruct()

{

$this->eventManager->trigger(new Event(self::ON_STOP, [

'key1' => 'val1'

]));

}

}

2. 此应用的监听器类

将每个事件的监听器写一个类,显得有些麻烦。我们可以只写一个类用里面不同的方法来处理不同的事件。

方式一: 类里面存在跟事件名称相同的方法(app.start -> start())

这种方式简单快捷,但是限定较死 - 事件名与方法的名称必须相同。

/**

* Class AppListener

* @package Inhere\Event\Examples

*/

class AppListener

{

public function start(EventInterface $event)

{

$pos = __METHOD__;

echo "handle the event{$event->getName()}on the:$pos\n";

}

public function beforeRequest(EventInterface $event)

{

$pos = __METHOD__;

echo "handle the event{$event->getName()}on the:$pos\n";

}

public function afterRequest(EventInterface $event)

{

$pos = __METHOD__;

echo "handle the event{$event->getName()}on the:$pos\n";

}

public function stop(EventInterface $event)

{

$pos = __METHOD__;

echo "handle the event{$event->getName()}on the:$pos\n";

}

}

方式二:实现接口 EventSubscriberInterface

有时候我们并不想将处理方法定义成事件名称一样,想自定义。

此时我们可以实现接口 EventSubscriberInterface,通过里面的 getSubscribedEvents() 来自定义事件和对应的处理方法

运行示例请看 examples/enum-group.php

/**

* Class EnumGroupListener

* @package Inhere\Event\Examples

*/

class EnumGroupListener implements EventSubscriberInterface

{

const TEST_EVENT = 'test';

const POST_EVENT = 'post';

/**

* 配置事件与对应的处理方法

* @return array

*/

public static function getSubscribedEvents(): array

{

return [

self::TEST_EVENT => 'onTest',

self::POST_EVENT => ['onPost', ListenerPriority::LOW], // 还可以配置优先级

];

}

public function onTest(EventInterface $event)

{

$pos = __METHOD__;

echo "handle the event{$event->getName()}on the:$pos\n";

}

public function onPost(EventInterface $event)

{

$pos = __METHOD__;

echo "handle the event{$event->getName()}on the:$pos\n";

}

}

3. 添加监听

// 这里使用 方式一

$em = new EventManager();

// register a group listener

$em->attach('app', new AppListener());

// create app

$app = new App($em);

// run.

$app->run();

4. 运行示例

完整的示例代码在 examples/named-group.php 中。

运行: php examples/named-group.php

输出:

$ php examples/named-group.php

handle the event 'app.start' on the: Inhere\Event\Examples\AppListener::start

handle the event 'app.beforeRequest' on the: Inhere\Event\Examples\AppListener::beforeRequest

request handling ....

handle the event 'app.afterRequest' on the: Inhere\Event\Examples\AppListener::afterRequest

handle the event 'app.stop' on the: Inhere\Event\Examples\AppListener::stop

事件通配符 *

支持使用事件通配符 * 对一组相关的事件进行监听, 分两种。

* 全局的事件通配符。直接对 * 添加监听器($em->attach('*', 'global_listener')), 此时所有触发的事件都会被此监听器接收到。

{prefix}.* 指定分组事件的监听。eg $em->attach('db.*', 'db_listener'), 此时所有触发的以 db. 为前缀的事件(eg db.query db.connect)都会被此监听器接收到。

当然,你在事件到达监听器前停止了本次事件的传播$event->stopPropagation(true);,就不会被后面的监听器接收到了。

示例,在上面的组事件监听器改下,添加一个 app.* 的事件监听。

// AppListener 新增一个方法

class AppListener

{

// ...

public function allEvent(EventInterface $event)

{

$pos = __METHOD__;

echo "handle the event '{$event->getName()}' on the:$pos\n";

}

}

// ...

$em = new EventManager();

$groupListener = new AppListener();

// register a group listener

$em->attach('app', $groupListener);

// all `app.` prefix events will be handled by `AppListener::allEvent()`

$em->attach('app.*', [$groupListener, 'allEvent']);

// create app

$app = new App($em);

// run.

$app->run();

运行示例

运行: php examples/named-group.php

输出:(可以看到每个事件都经过了AppListener::allEvent()的处理)

$ php examples/named-group.php

handle the event 'app.start' on the: Inhere\Event\Examples\AppListener::start

handle the event 'app.start' on the: Inhere\Event\Examples\AppListener::allEvent

handle the event 'app.beforeRequest' on the: Inhere\Event\Examples\AppListener::beforeRequest

handle the event 'app.beforeRequest' on the: Inhere\Event\Examples\AppListener::allEvent

request handling ....

handle the event 'app.afterRequest' on the: Inhere\Event\Examples\AppListener::afterRequest

handle the event 'app.afterRequest' on the: Inhere\Event\Examples\AppListener::allEvent

handle the event 'app.stop' on the: Inhere\Event\Examples\AppListener::stop

handle the event 'app.stop' on the: Inhere\Event\Examples\AppListener::allEvent

事件对象

事件对象 - 装载了在触发事件时相关的上下文信息,用户自定义的。

预先创建一个事件

直接简单的使用类 Event

$myEvent = new Event('name', 'target', [ 'some params ...' ]);

使用继承了 Event 的子类

这样你可以追加自定义数据

// create event class

class MessageEvent extends Event

{

protected $name = 'messageSent';

// append property ...

public $message;

}

License

MIT

本文标签: event php php