-
Quick start, (*13)
use Phossa2\Event\EventDispatcher;
// event dispatcher
$events = new EventDispatcher();
// bind event with a callback
$events->attach('login.success', function($evt) {
echo "logged in as ". $evt->getParam('username');
});
// bind event with a callable
$events->attach('login.attempt', [$logger, 'logEvent']);
// unbind an event
$events->clearListeners('login.attempt');
// fire the trigger
$events->trigger('login.success');
-
Event name globbing, (*14)
Event name globbing means callables of the binding 'login.*' will also be
triggered when triggering event 'login.success'., (*15)
// bind 'login.*' with callables
$events->attach('login.*', function($evt) {
echo $evt->getName();
});
// trigger 'login.atttempt' will also trigger callables of 'login.*'
$events->trigger('login.attempt');
The globbing rules are similiar to the PHP function glob()
, where, (*16)
-
*
in the string means any chars except the dot., (*17)
-
If *
at the end, will match any chars including the dot. e.g. login.*
will match 'login.attempt.before'., (*18)
-
.
means the dot., (*19)
-
one-char-string *
means match any string (including the dot)., (*20)
Note: Name globbing ONLY happens when event is being triggered.
Binding or unbinding events only affect the EXACT event name., (*21)
// unbind the exact 'login.*'
$events->clearListeners('login.*');
-
Shared event manager support, (*22)
Class EventDispatcher
implements the Phossa2\Shared\Shareable\ShareableInterface
., (*23)
ShareableInterface
is an extended version of singleton pattern. Instead of
supporting only one shared instance, Classes implements ShareableInterface
may have shared instance for different scope
., (*24)
// global event manager, global scope is ''
$globalEvents = EventDispatcher::getShareable();
// shared event manager in scope 'MVC'
$mvcEvents = EventDispatcher::getShareable('MVC');
// an event manager instance, which has scope 'MVC'
$events = new EventDispatcher('MVC');
// in scope MVC ?
var_dump($events->hasScope('MVC')); // true
// in global scope ?
var_dump($events->hasScope()); // true
Callables bound to a shared manager will also be triggered if an event manager
instance has the same scope., (*25)
// shared event manager in scope 'MVC'
$mvcEvents = EventDispatcher::getShareable('MVC');
// bind with pirority 100 (highest priority)
$mvcEvents->attach('*', function($evt) {
echo "mvc";
}, 100);
// create a new instance within the MVC scope
$events = new EventDispatcher('MVC');
// bind with default priority 0
$events->attach('test', function($evt) {
echo "test";
});
// will also trigger matched events in $mvcEvents
$events->trigger("test");
Event manager instance can have multiple scopes, either specified during the
instantiation or using addScope()
., (*26)
// create an event manager with 2 scopes
$events = new EventDispatcher(['MVC', 'AnotherScope']);
// add another scope
$events->addScope('thirdScope');
Couple of helper methods are provided for on/off/trigger events with shared
managers., (*27)
// bind a callable to global event manager
EventDispatcher::onGlobalEvent('login.success', function() {});
// use interface name as a scope
EventDispatcher::onEvent(
'Psr\\Log\\LoggerInterface', // scope
'log.error', // event name
function () {}
);
// unbind all callables of event 'log.error' in a scope
EventDispatcher::offEvent(
'Psr\\Log\\LoggerInterface',
'log.error'
);
// unbind *ALL* events in global scope
EventDispatcher::offGlobalEvent();
-
Attaching a listener, (*28)
Listener
implements the ListenerInterface
. Or in short, provides a method
eventsListening()
., (*29)
use Phossa2\Event\Interfaces\ListenerInterface;
class myListener implements ListenerInterface
{
public function eventsListening()
{
return [
// one method of $this
eventName1 => 'method1',
// 2 methods
eventName2 => ['callable1', 'method2'],
// priority 20 and in a 'mvcScope' scope
eventName2 => ['method2', 20, 'mvcScope'], // with priority 20
eventName3 => [
['method3', 50],
['method4', 70, 'anotherScope']
]
];
}
}
EventDispatcher::attachListener()
can be used to bind events defined in
eventsListening()
instead of using EventDispatcher::attach()
to bind each
event manually., (*30)
$events = new EventDispatcher();
$listener = new \myListener();
// bind all events defined in $listener->eventsListening()
$events->attachListener($listener);
// will call $listener->method1()
$events->trigger('eventName1');
-
Using event manager statically, (*31)
StaticEventDispatcher
is a static wrapper for an EventDispatcher
slave., (*32)
StaticEventDispatcher::attach('*', function($evt) {
echo 'event ' . $evt->getName();
});
// will print 'event test'
StaticEventDispatcher::trigger('test');
StaticEventDispatcher
is not the same as global event manager.
StaticEventDispatcher
has a default slave which is a shared event manager
in scope '__STATIC__'
. While global event manager is the shared event
manager in global scope ''
., (*33)
User may set another event manager to replace the default slave., (*34)
StaticEventDispatcher::setEventManager(new EventDispatcher());
-
EventCapableAbstract
, (*35)
EventCapableAbstract
implements both ListenerInterface
and
EventCapableInterface
. It will do the following when triggerEvent()
is called,, (*36)
-
Get the event manager. If it is not set yet, create one default event
manager with current classname as scope., (*37)
-
Attach events defined in eventsListening()
if not yet., (*38)
-
Trigger the event and processed by the event manager and all of the
shared managers of its scopes., (*39)
class LoginController extends EventCapableAbstract
{
public function login() {
// failed
if (!$this->trigger('login.pre')) {
return;
}
// ...
}
public function beforeLogin() {
// ...
}
public function eventsListening()
{
return [
'login.pre' => 'beforeLogin'
];
}
}
-
EventableExtensionAbstract
and EventableExtensionCapableAbstract
, (*40)
EventableExtensionCapableAbstract
is the base class supporting events and
extensions., (*41)
Detail usage can be found in phossa2/cache
Phossa2\Cache\CachePool
extends EventableExtensionCapableAbstract
and
Phossa2\Cache\Extension\ByPass
extends EventableExtensionAbstract
., (*42)
Or look at phossa2/route., (*43)
-
Class or interface level events support, (*44)
Class or interface name can be used as the scope
. When events bound to these
kind of scopes, any events triggered by child class will also search callables
defined in parent class/interface level shared event managers., (*45)
// define event '*' for interface 'MyInterface'
EventDispatcher::onEvent(
'MyInterface', '*', function() { echo "MyInterface"; }, 60
);
Extends EventCapableAbstract
., (*46)
class MyClass extends EventCapableAbstract implements MyInterface
{
public function myMethod()
{
echo "myMethod";
}
public function eventsListening()/*# : array */
{
return [
// priority 20
'afterTest' => ['myMethod', 20]
];
}
}
$obj = new MyClass();
// will trigger callable 'myMethod' and handlers for 'MyInterface'
$obj->trigger('afterTest');
-
Execute callable for limited times, (*47)
// bind a callable for executing only once
$events->one('user.login', function(Event $evt) {
// ...
});
// 3 times
$events->many(3, 'user.tag', function(Event $evt) {
// ...
});