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 相关文章推荐
一个odbc连mssql分页的类
Oct 09 PHP
php 需要掌握的东西 不做浮躁的人
Dec 28 PHP
Cakephp 执行主要流程
Mar 24 PHP
PHP面向对象三大特点学习(充分理解抽象、封装、继承、多态)
May 07 PHP
一个PHP针对数字的加密解密类
Mar 20 PHP
php批量删除数据库下指定前缀的表以prefix_为例
Aug 24 PHP
php基于mcrypt的加密解密实例
Oct 27 PHP
8个必备的PHP功能开发
Oct 02 PHP
PHP页面跳转实现延时跳转的方法
Dec 10 PHP
PHP简单留言本功能实现代码
Jun 09 PHP
搭建自己的PHP MVC框架详解
Aug 16 PHP
Laravel学习笔记之Artisan命令生成自定义模板的方法
Nov 22 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 数组入门教程小结
2009/05/20 PHP
PHP foreach循环使用详解与实例代码
2010/05/08 PHP
php中常用字符串处理代码片段整理
2011/11/07 PHP
最简单的jQuery程序 入门者学习
2009/07/09 Javascript
window.ActiveXObject使用说明
2010/11/08 Javascript
jquery中:input和input的区别分析
2011/07/13 Javascript
js中onload与onunload的使用示例
2013/08/25 Javascript
javascript模块化是什么及其优缺点介绍
2013/09/02 Javascript
用Js实现的动态增加表格示例自己写的
2013/10/21 Javascript
JQuery获取或设置ckeditor的数据(示例代码)
2013/11/15 Javascript
jquery获取radio值实例
2014/10/16 Javascript
JSONP之我见
2015/03/24 Javascript
详细解密jsonp跨域请求
2015/04/15 Javascript
jQuery简单实现input文本框内灰色提示文本效果的方法
2015/12/02 Javascript
浅谈jquery上下滑动的注意事项
2016/10/13 Javascript
Vue2.0 vue-source jsonp 跨域请求
2017/08/04 Javascript
Node.js JSON模块用法实例分析
2019/01/04 Javascript
js中offset,client , scroll 三大元素知识点总结
2019/09/11 Javascript
这15个Vue指令,让你的项目开发爽到爆
2019/10/11 Javascript
python引用DLL文件的方法
2015/05/11 Python
简单介绍Python中的decode()方法的使用
2015/05/18 Python
python利用OpenCV2实现人脸检测
2020/04/16 Python
pandas数据预处理之dataframe的groupby操作方法
2018/04/13 Python
python 遍历目录(包括子目录)下所有文件的实例
2018/07/11 Python
Python 获取主机ip与hostname的方法
2018/12/17 Python
提升Python程序性能的7个习惯
2019/04/14 Python
TensorFlow命名空间和TensorBoard图节点实例
2020/01/23 Python
win10下opencv-python特定版本手动安装与pip自动安装教程
2020/03/05 Python
amazeui树节点自动展开折叠面板并选中第一个树节点的实现
2020/08/24 HTML / CSS
几道数据库的概念性面试题
2014/05/30 面试题
商务日语专业自荐信
2014/04/17 职场文书
平安工地建设方案
2014/05/06 职场文书
房屋租赁合同补充协议
2014/10/11 职场文书
五年级学生期末评语
2014/12/26 职场文书
利用html+css实现菜单栏缓慢下拉效果的示例代码
2021/03/30 HTML / CSS
vue项目配置sass及引入外部scss文件
2022/04/14 Vue.js