Zend Framework 2.0事件管理器(The EventManager)入门教程


Posted in PHP onAugust 11, 2014

概述

EventManger是一个为以下使用情况设计的组件:

实现简单的主题/观察者模式

实现面向切面的设计

实现事件驱动的架构

基本的架构允许你添加和解除指定事件的侦听器,无论是在一个实例基础还是一个共享的集合;触发事件;终止侦听器的执行。

快速入门

通常,你将会在一个类中创建一个EventManager。

use Zend\EventManager\EventManagerInterface;

use Zend\EventManager\EventManager;

use Zend\EventManager\EventManagerAwareInterface;

 

class Foo implements EventManagerAwareInterface

{

    protected $events;

 

    public function setEventManager(EventManagerInterface $events)

    {

        $events->setIdentifiers(array(

            __CLASS__,

            get_called_class(),

        ));

        $this->events = $events;

        return $this;

    }

 

    public function getEventManager()

    {

        if (null === $this->events) {

            $this->setEventManager(new EventManager());

        }

        return $this->events;

    }

}

上面的代码允许用户访问EventManager实例,或使用一个新的实例重置它;如果不存在,它将会在被用到的时候惰性实例化。

EventManager仅仅对它是否触发了一些事件感兴趣。基础的触发接受三个参数:事件的名字,它通常是当前的函数/方法名;上下文,它通常是当前的对象的实例;和参数,它通常是提供给当前函数/方法的参数。

class Foo

{

    // ... assume events definition from above

 

    public function bar($baz, $bat = null)

    {

        $params = compact('baz', 'bat');

        $this->getEventManager()->trigger(__FUNCTION__, $this, $params);

    }

}

按顺序,触发事件仅关心否有一些东西侦听了事件。侦听器添加到EventManager,指定一个指定的事件和要通知的回调。回调接受一个Event对象,它有一个用于获取事件名字,上下文和参数的访问器。让我们添加一个侦听器,并且触发事件。

use Zend\Log\Factory as LogFactory;

 

$log = LogFactory($someConfig);

$foo = new Foo();

$foo->getEventManager()->attach('bar', function ($e) use ($log) {

    $event  = $e->getName();

    $target = get_class($e->getTarget());

    $params = json_encode($e->getParams());

 

    $log->info(sprintf(

        '%s called on %s, using params %s',

        $event,

        $target,

        $params

    ));

});

 

// Results in log message:

$foo->bar('baz', 'bat');

// reading: bar called on Foo, using params {"baz" : "baz", "bat" : "bat"}"

注意,attach()的第二个参数是一个任何有效的回调;例子中展示了一个匿名函数来保持例子是自包含的。然而,你同样可以使用一个有效的函数名字,一个函数对象,一个引用静态方法的字符串,或一个带有一个指定静态方法或实例方法的回调数组。再一次,任何PHP回调都是有效的。

有时候你可能想要指定一个侦听器没有一个创建了一个EventManager的类的对象实例。Zend Framework通过一个SharedEventCollection的概念来实现它。简单的说,你可以使用一个众所周知的SharedEventCollection来注入一个独立的EventManager实例,并且EventManager实例将会为附加的侦听器来查询它。添加到SharedEventCollection的侦听器与正常的事件管理器大略相同;调用attach与EventManager完全相同,但是在开始需要一个附加的参数:一个指定的实例。还记得创建一个EventManager的实例,我们是如何传递给他__CLASS__的?在使用一个SharedEventCollection时,那个值,或者任何你提供给构造器的数组中的任何字符串,可能用于识别一个实例。作为一个示例,假设我们有一个SharedEventManager实例我们知道已经被注入到我们的EventManager实例中了(对于实例,通过依赖注入),我们可以更改上面的例子来通过共享集合来添加:

use Zend\Log\Factory as LogFactory;

 

// Assume $events is a Zend\EventManager\SharedEventManager instance

 

$log = LogFactory($someConfig);

$events->attach('Foo', 'bar', function ($e) use ($log) {

    $event  = $e->getName();

    $target = get_class($e->getTarget());

    $params = json_encode($e->getParams());

 

    $log->info(sprintf(

        '%s called on %s, using params %s',

        $event,

        $target,

        $params

    ));

});

 

// Later, instantiate Foo:

$foo = new Foo();

$foo->getEventManager()->setSharedEventCollection($events);

 

// And we can still trigger the above event:

$foo->bar('baz', 'bat');

// results in log message:

// bar called on Foo, using params {"baz" : "baz", "bat" : "bat"}"

注意:StaticEventManager

在2.0.0beta3中,你可以使用StaticEventManager单例作为一个SharedEventCollection。这样,你不需要担心在哪或者如何来访问SharedEventCollection;它通过简单的调用StaticEventManager::getInstance()是全局可用的。

要知道,然而,框架不赞成它的使用,并且在2.0.0beta4中,你将通过配置一个SharedEventManager实例并注入到一个单独的EventManager实例中来代替它。

通配符侦听器

有时候你可能会想要为一个给定的实例的很多事件或全部事件添加相同的侦听器,或者可能,使用一个共享事件集合,很多上下文,并且很多事件。EventManager组件允许这样做。

一次添加多个事件

$events = new EventManager();

$events->attach(array('these', 'are', 'event', 'names'), $callback);

通过通配符添加

$events = new EventManager();

$events->attach('*', $callback);

注意如果你指定了一个优先级,那个优先级将会用于这个侦听器触发的任何事件。

上面的代码指定的是任何时间触发将会导致这个特定侦听器的通知。

通过一个SharedEventManager一次添加多个事件

$events = new SharedEventManager();

// Attach to many events on the context "foo"

$events->attach('foo', array('these', 'are', 'event', 'names'), $callback);

 

// Attach to many events on the contexts "foo" and "bar"

$events->attach(array('foo', 'bar'), array('these', 'are', 'event', 'names'), $callback);

注意如果你指定了一个优先级,那个优先级将会被用于所有指定的事件。

通过一个SharedEventManager一次添加所有事件

$events = new SharedEventManager();

// Attach to all events on the context "foo"

$events->attach('foo', '*', $callback);

 

// Attach to all events on the contexts "foo" and "bar"

$events->attach(array('foo', 'bar'), '*', $callback);

注意如果你指定了一个优先级,那个优先级将会被用于所有指定的事件。

上面的代码指定了上下文“foo”和“bar”,指定的侦听器将会在任何事件触发时被通知。

配置选项

EventManager选项

标识符

给定的EventManager实例可以回答的字符串或字符串数组,当通过一个SharedEventManager访问时。

event_class

一个替代的Event类的名字用于代表传给侦听器的事件。

shared_collections

当触发事件时的一个SharedEventCollection实例。

可用方法

__construct

__construct(null|string|int Sidentifier)

构造一个新的EventManager实例,使用给定的标识符,如果提供了的话,为了共享集合的目的。

setEventClass

setEventClass(string $class)

提供替换Event类的名字用在创建传递给触发的侦听器的事件时。

setSharedCollections

setSharedCollections(SharedEventCollection $collections=null)

用于触发事件时的SharedEventCollection实例。

getSharedCollections

getSharedCollections()

返回当前添加到的SharedEventCollection实例。如果没有添加集合,返回空,或者一个SharedEventCollection实例。

trigger

trigger(string $event, mixed $target, mixed $argv, callback $callback)

触发指定事件的所有侦听器。推荐为$event使用当前的函数/方法名,在后面加上诸如“.pre”、“.post”等,如果有需要的话。$context应该是当前对象的实例,或者是函数的名字如果不是使用对象触发。$params通常应该是一个关联数组或者ArrayAccess实例;我们推荐使用传递给函数/方法的参数(compact()在这里通常很有用处)。这个方法同样可以接受一个回调并且表现与triggerUntil()相同。

方法返回一个ResponseCollection的实例,它可以用于反省各种各样的侦听器返回的值,测试短路,以及更多。

triggerUntil

triggerUntil(string $event, mixed $context, mixed $argv, callback $callback)

触发指定事件的所有侦听器,就像trigger(),额外的是它将每个侦听器的返回值传递给$callback;如果$callback返回一个布尔true值,侦听器的执行将被终止。你可以使用$result->stopped()来测试它。

attach

attach(string $event, callback $callback, int $priority)

添加$callback到EventManager实例,侦听事件$event。如果提供了一个$priority,侦听器将会使用那个优先级插入到内部的侦听器堆栈;高的值会先执行。(默认的优先级是“1”,并且运行使用负的值。)

方法返回一个Zend\Stdlib\CallbackHandler的实例;这个值可以在稍后传递给detach(),如果需要的话。

attachAggregate

attachAggregate(string|ListenerAggregate $aggregate)

如果一个字符串被传递作为$aggregate,实例化那个类。$aggregate然后被传递给EventManager实例的attache()方法因此他可以注册侦听器。

返回ListenerAggregate实例。

detach

detach(CallbackHandler $listener)

扫描所有的侦听器,并且取消匹配$listener的所有侦听器因此它们将不再会被触发。

返回一个true布尔值如果任何侦听器已经被指定并且取消订阅,否则返回一个false布尔值。

detachAggregate

detachAggregate(ListenerAggregate $aggregate)

循环所有的事件来确定集合代表的侦听器;对于所有的匹配项,侦听器将会被移除。

如果任何侦听器被确定并被取消订阅返回一个true布尔值,否则返回一个false布尔值。

getEvents

getEvent()

返回一个有侦听器附加的所有事件名字的数组。

getListeners

getListeners(string $event)

返回一个添加到$event的所有侦听器的Zend\Stdlib\PriorityQueue实例

clearListeners

clearListeners(string $event)

移除添加到$event的所有侦听器。

prepareArgs

prepareArgs(array $args)

从提供的$args创建一个ArrayObject。如果你想要你的侦听器可以更改参数让稍后的侦听器或触发的方法可以看到这些更改的情况下着将很有用。

PHP 相关文章推荐
一个分页的论坛
Oct 09 PHP
PHP导出MySQL数据到Excel文件(fputcsv)
Jul 03 PHP
php和js如何通过json互相传递数据相关问题探讨
Feb 26 PHP
两级联动select刷新后其值保持不变的实现方法
Jan 27 PHP
ThinkPHP模板比较标签用法详解
Jun 30 PHP
php 从指定数字中获取随机组合的简单方法(推荐)
Apr 05 PHP
PHP实现的常规正则验证helper公共类完整实例
Apr 27 PHP
PHP实现网站访问量计数器
Oct 27 PHP
php将从数据库中获得的数据转换成json格式并输出的方法
Aug 21 PHP
PHP抽象类与接口的区别详解
Mar 21 PHP
PHP实现单文件、多个单文件、多文件上传函数的封装示例
Sep 02 PHP
php接口隔离原则实例分析
Nov 11 PHP
php向js函数传参的几种方法
Aug 10 #PHP
本地计算机无法启动Apache故障处理
Aug 08 #PHP
浅析PHP编程中10个最常见的错误
Aug 08 #PHP
ThinkPHP自动转义存储富文本编辑器内容导致读取出错的解决方法
Aug 08 #PHP
PHP连接sql server 2005环境配置及问题解决
Aug 08 #PHP
getJSON跨域SyntaxError问题分析
Aug 07 #PHP
PHP+FastCGI+Nginx配置PHP运行环境
Aug 07 #PHP
You might like
PHP面向对象三大特点学习(充分理解抽象、封装、继承、多态)
2012/05/07 PHP
php使用base64加密解密图片示例分享
2014/01/20 PHP
PHP程序员必须清楚的问题汇总
2014/12/18 PHP
PHP判断IP并转跳到相应城市分站的方法
2015/03/25 PHP
WampServer搭建php环境时遇到的问题汇总
2015/07/23 PHP
php实现微信公众号无限群发
2015/10/11 PHP
PHP魔术方法之__call与__callStatic使用方法
2017/07/23 PHP
document.createElement()用法及注意事项(ff下不兼容)
2013/03/13 Javascript
封装html的select标签的js操作实例
2013/07/02 Javascript
js/jQuery简单实现选项卡功能
2014/01/02 Javascript
js中传递特殊字符(+,&)的方法
2014/01/16 Javascript
jQuery自定义添加"$"与解决"$"冲突的方法
2015/01/19 Javascript
jQuery在线选座位插件seat-charts特效代码分享
2015/08/27 Javascript
基于jQuery实现自动轮播旋转木马特效
2015/11/02 Javascript
实用又漂亮的BootstrapValidator表单验证插件
2016/05/30 Javascript
js实现移动端轮播图效果
2020/12/09 Javascript
微信小程序常用简易小函数总结
2019/02/01 Javascript
Nodejs监听日志文件的变化的过程解析
2019/08/04 NodeJs
[00:47]DOTA2荣耀之路6:天火,天火!
2018/05/30 DOTA
使用Python生成XML的方法实例
2017/03/21 Python
Python 创建空的list,以及append用法讲解
2018/05/04 Python
python3将视频流保存为本地视频文件
2018/06/20 Python
使用Python实现文字转语音并生成wav文件的例子
2019/08/08 Python
使用PyCharm安装pytest及requests的问题
2020/07/31 Python
Unix如何在一行中运行多个命令
2015/05/29 面试题
应聘美工求职信
2013/11/07 职场文书
汽车专业学生自我评价
2014/01/19 职场文书
采购主管岗位职责
2014/02/01 职场文书
就业协议书怎么填
2014/09/15 职场文书
机关职员工作检讨书
2014/10/23 职场文书
党员四风问题个人对照检查材料
2014/10/26 职场文书
高中生个性发展自我评价
2015/03/09 职场文书
文明礼貌主题班会
2015/08/14 职场文书
小学生禁毒教育心得体会
2016/01/15 职场文书
家长必看:义务教育,不得以面试 评测等名义选拔学生
2019/07/09 职场文书
中国十大神话动漫电影排行榜 哪吒登顶 白蛇缘起排第七
2022/03/21 国漫