PHP中EventDispatcher事件分发组件的详细分析

 更新时间:2016年12月31日 09:44  点击:2147
这篇文章详解了PHP中EventDispatcher事件分发组件,插件可以添加一些方法,或者在某些方法执行之前或者之后做些事情,而不干扰其他插件。有需要的同学可以参考一下

引言

考虑这样一个问题,现在你想给为你的项目提供一个插件系统,插件可以添加一些方法,或者在某些方法执行之前或者之后做些事情,而不干扰其他插件。要实现这个系统,简单的单继承不是个好办法,即使多继承在PHP中是可能的,他也有与生俱来的缺点(多继承不太了解,感觉挺操蛋的)。

Symfony EventDispatcher以一个简单有效的方式实现了中介者模式,事件分发器就是那个中介,让系统和插件不会耦合在一起,这让上面的插件系统成为可能,而且他会让你的项目可扩展性更好。

上面的话,翻译自Symfony官方文档片段

系统剖析

事件存储

上面这张图是分析Symfony EventDispatcher组件源码得出来的,可以看到事件在系统中是如何存储的

这里面将事件存储了两遍,用来加入优先级priority的概念,存如的时候放入上图中上面的结构中,取出时候从上图中下面的结构中拿出来,相同的事件名称可以有不同的优先级,优先级越高的事件优先触发,优先级相同的时候,先插入的事件优先触发。

排序事件(上图中下面的结构)在插入事件的时候不会构建,而是当取出事件的时候会生成排好序的事件,当相同的事件名中插入新的事件或删除某个事件的时候,会删除对应的排好序的事件名,后面用到的时候重新构建

执行事件的时候,会获取对应事件名排好序的linster列表,按照顺序依次执行。

事件执行

如上图所示,当触发某个时间的时候,该事件名下面如果监听了多个触发动作,他们会按照优先级、注册顺序依次触发,触发动作一般是一个可执行的“实例”(不管是类还是函数,必须可以通过call_user_func_array调用),可以传入三个参数,第一个参数(必须)是一个Event实例,第二个是触发的事件名,第三个是事件分发器实例。第一个参数会控制事件是否在该事件名下的所有触发动作之间继续传递,比如上面的linstener_2里面将Event.propagationStopped设置为true,执行完linstener_2后,事件就会停止传播,linstener_2后面的动作不会触发。

除此之外,Event实例中还可以保存其他必要的信息,以便linstener触发执行的时候,获取额外的信息。

事件订阅者

事件订阅者(Event subscriber),告诉dispathcer实例,他要订阅的所有事件,不用一个个通过dispathcer实例去注册。事件订阅者是一个PHP类,他可以告诉dispathcer他要订阅的具体的事件。

好处:

  • 关注的事件不用一个个去注册。
  • 取消关注的事件不用一个个去移除注册。

订阅者内部关注的事件是一个整体,要么全部关注要么全部不关注

实例

普通栗子

include"vendor/autoload.php";
useSymfony\Component\EventDispatcher\EventDispatcher;
useSymfony\Component\EventDispatcher\Event;
classUserEventextendsEvent
{
 publicfunctionname()
 {
 return"Cartman";
 }
 
 publicfunctionage()
 {
 return"24";
 }
}
$dispatcher=newEventDispatcher();
$dispatcher->addListener("user.name",function($event,$eventName,$dispatcher){
 echo"My name is Cartman\n";
});
$dispatcher->addListener("user.name",function($event,$eventName,$dispatcher){
 echo"My name is {$event->name()} from Event instance\n";
}, 10);
$dispatcher->addListener("user.age",function($event,$eventName,$dispatcher){
 echo"My age is 24\n";
}, 10);
$dispatcher->addListener("user.age",function($event,$eventName,$dispatcher){
 echo"My age is {$event->age()} from Event instance\n";
}, -10);
$dispatcher->dispatch("user.name",newUserEvent());
$dispatcher->dispatch("user.age",newUserEvent());

上面的例子输出

My name is Cartman from Event instance
My name is Cartman
My age is 24
My age is 24 from Event instance

事件订阅者栗子

通过Subscriber注册事件

include"vendor/autoload.php";
useSymfony\Component\EventDispatcher\EventDispatcher;
useSymfony\Component\EventDispatcher\Event;
useSymfony\Component\EventDispatcher\EventSubscriberInterface;
classBookEventextendsEvent
{
 public$name= self::class;
}
classBookSubscriberimplementsEventSubscriberInterface
{
 publicstaticfunctiongetSubscribedEvents()
 {
 return[
  "chinese.name"=>"chineseNameShow",
  "english.name"=> [
  ["englishNameShow", -10],
  ["englishNameAFter", 10],
  ],
  "math.name"=> ["mathNameShow", 100]
 ];
 }
 publicfunctionchineseNameShow(Event$event)
 {
 echo"我是汉语书籍\n";
 }
 publicfunctionenglishNameShow(Event$event)
 {
 echo"我是英文书籍\n";
 }
 publicfunctionenglishNameAFter(Event$event)
 {
 echo"我是展示之后的英文书籍[来自于Event实例{$event->name}]\n";
 }
 publicfunctionmathNameShow(Event$event)
 {
 echo"我是展示的数学书籍\n";
 }
}
$dispatcher=newEventDispatcher();
$subscriber=newBookSubscriber();
$dispatcher->addSubscriber($subscriber);
$dispatcher->dispatch("english.name",newBookEvent());
$dispatcher->dispatch("chinese.name");
$dispatcher->removeSubscriber($subscriber);
$dispatcher->dispatch("math.name");

输出为内容:

我是展示之后的英文书籍[来自于Event实例BookEvent]
我是英文书籍
我是汉语书籍
本篇php中urlencode()和urldecode()URL编码函数浅析将为大家介绍这两种函数的实现方式,有兴趣的同学快来看看吧。

URLEncode:是指针对网页url中的中文字符的一种编码转化方式,最常见的就是Baidu、Google等搜索引擎中输入中文查询时候,生成经过Encode过的网页URL。

URLEncode的方式一般有两种,一种是传统的基于GB2312的Encode(Baidu、Yisou等使用),另一种是基于UTF-8的Encode(Google、Yahoo等使用)。

URLdecode:就是将url编码后的字符串还原成未编码的样子。

本工具分别实现两种方式的Encode与Decode:

中文 -> GB2312的Encode -> %D6%D0%CE%C4

中文 -> UTF-8的Encode -> %E4%B8%AD%E6%96%87

Html中的URLEncode:

编码为GB2312的html文件中:http://www.php2.cc/中文.rar -> 浏览器自动转换为 -> http://www.php2.cc/%D6%D0%CE%C4.rar

注意:Firefox对GB2312的Encode的中文URL支持不好,因为它默认是UTF-8编码发送URL的,但是ftp://协议可以,我试过了,我认为这应该算是Firefox一个bug。

编码为UTF-8的html文件中:http://www.php2.cc/中文.rar -> 浏览器自动转换为 -> http://www.php2.cc/%E4%B8%AD%E6%96%87.rar

PHP中的URLEncode:

1 2 //GB2312的Encode
3 echo urlencode("中文-_. ")."\n"; //%D6%D0%CE%C4-_.+
4 echo urldecode("%D6%D0%CE%C4-_. ")."\n"; //中文-_.
5 echo rawurlencode("中文-_. ")."\n"; //%D6%D0%CE%C4-_.%20
6 echo rawurldecode("%D6%D0%CE%C4-_. ")."\n"; //中文-_.
7 ?>
除了“-_.”之外的所有非字母数字字符都将被替换成百分号“%”后跟两位十六进制数。

urlencode和rawurlencode的区别:urlencode将空格编码为加号“+”,rawurlencode将空格编码为加号“%20”。

如果要使用UTF-8的Encode,有两种方法:
一、将文件存为UTF-8文件,直接使用urlencode、rawurlencode即可。

二、使用mb_convert_encoding函数:

1 2 $url = 'http://www.php2.cc/中文.rar';
3 echo urlencode(mb_convert_encoding($url, 'utf-8', 'gb2312'))."\n";
4 echo rawurlencode(mb_convert_encoding($url, 'utf-8', 'gb2312'))."\n";
5 //http%3A%2F%2Fwww.php2.cc%2F%E4%B8%AD%E6%96%87.rar
6 ?>
实例:
 1  2 function parseurl($url="")
 3 {
 4 $url = rawurlencode(mb_convert_encoding($url, 'gb2312', 'utf-8'));
 5 $a = array("%3A", "%2F", "%40");
 6 $b = array(":", "/", "@");
 7 $url = str_replace($a, $b, $url);
 8 return $url;
 9 }
10 $url="ftp://ud03:password@www.php2.cc/中文/中文.rar";
11 echo parseurl($url);
12 //ftp://ud03:password@www.php2.cc/%D6%D0%CE%C4/%D6%D0%CE%C4.rar
13 ?>
JavaScript中的URLEncode:

如:%E4%B8%AD%E6%96%87-_.%20%E4%B8%AD%E6%96%87-_.%20

encodeURI不对下列字符进行编码:“:”、“/”、“;”、“?”、“@”等特殊字符。

php怎么禁用eval() 函数?在下文一聚教程网为大家带来了实例分析,想要知道的同学快来看看吧。

php eval() 函数操作数组:

<?php
$data = "array('key1'=>'value1','key2'=>'value2','key3'=>'value3','key4'=>'value4')";
$arr = eval("return $data;");
var_dump($arr); //array
?>

运行结果:

array(4) { ["key1"]=> string(6) "value1" ["key2"]=> string(6) "value2" ["key3"]=> string(6) "v

网上很多说使用disable_functions禁止掉eval的方法都是错误的!

其实eval()是无法用php.ini中的disable_functions禁止掉的 :

because eval() is a language construct and not a function

eval是zend的,因此不是PHP_FUNCTION 函数;

那么php怎么禁止eval呢?

如果想禁掉eval可以用php的扩展 Suhosin:

安装Suhosin后在php.ini中load进来Suhosin.so,再加上suhosin.executor.disable_eval = on即可

下面我们来关注一篇关于php中telnet命令发送邮件演示,希望文章能够对各位带来帮助,具体的细节如下介绍.

我们平时常用telnet命令来检测某个端口是否是通的,但它的功能远远不止如此。它可以用来登陆,还可以用来发邮件。以下是完整的范例。

[root@d23334634]# telnet smtp.111cn.net 25
Trying 42.120.219.29...
Connected to smtp.111cn.net.
Escape character is '^]'.
220 smtp.aliyun-inc.com MX AliMail Server(10.147.40.200)
helo 123         --这里可以随便输入一些字符,不一定是“123”。目的是给服务器打个招呼
250 Ok
auth login    --然后输入auth login,开始登陆
334 dXNlcm5hbWU6
d2ViQGRhaXhpYW9ydWkuY29t    --邮箱名base64后(如:web@111cn.net base64后变成了d2ViQGRhaXhpYW9ydWkuY29t)
334 UGFzc3dvcmQ6
Qdgwehhh333333    --邮箱密码base64后
235 Authentication successful
mail from:<web@111cn.net>   --发件人邮箱
250 Mail Ok
rcpt to:<446673330@qq.com>   --收件人邮箱,可以是多个
250 Rcpt Ok
data    --开始输入发件信息
354 End data with <CR><LF>.<CR><LF>
from:web@111cn.net
subject:这里是邮件的标题

这里是邮件的正文,注意要与上面空一行。    --注意标题输完后,要多空一行
正文正文,abcdefg www.111cn.net hello hello.

.
250 Data Ok: queued as freedom

[!--infotagslink--]

相关文章

  • Vue组件跨层级获取组件操作

    这篇文章主要介绍了Vue组件跨层级获取组件操作,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧...2020-07-28
  • C#事件(event)使用方法详解

    本文给大家介绍了在C#中,事件(event)的概念和使用方法,文章适合一些初学者学习,主要讲解了一些概念和一些代码案例。...2020-06-25
  • jQuery事件绑定用法详解(附bind和live的区别)

    这篇文章主要介绍了jQuery事件绑定用法,结合实例形式较为详细的分析了jQuery事件绑定的实现原理与相关注意事项,并附带了相关绑定方法的使用说明,重点介绍了bind和live的区别,需要的朋友可以参考下...2016-01-21
  • Vue实现动态查询规则生成组件

    今天我们来给大家介绍下在Vue开发中我们经常会碰到的一种需求场景,本文主要介绍了Vue动态查询规则生成组件,需要的朋友们下面随着小编来一起学习学习吧...2021-05-27
  • Vue 组件复用多次自定义参数操作

    这篇文章主要介绍了Vue 组件复用多次自定义参数操作,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧...2020-07-27
  • Vue 过渡(动画)transition组件案例详解

    这篇文章主要介绍了Vue 过渡(动画)transition组件案例详解,非常不错,具有参考借鉴价值,需要的朋友参考下...2017-01-26
  • js组件SlotMachine实现图片切换效果制作抽奖系统

    这篇文章主要介绍了js组件SlotMachine实现图片切换效果制作抽奖系统的相关资料,需要的朋友可以参考下...2016-04-19
  • MYSQL事务回滚的2个问题分析

    因此,正确的原子操作是真正被执行过的。是物理执行。在当前事务中确实能看到插入的记录。最后只不过删除了。但是AUTO_INCREMENT不会应删除而改变值。1、为什么auto_increament没有回滚?因为innodb的auto_increament的...2014-05-31
  • vue中使用element日历组件的示例代码

    这篇文章主要介绍了vue中如何使用element的日历组件,本文通过实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下...2021-09-30
  • easyUI下拉列表点击事件使用方法

    这篇文章主要为大家详细介绍了easyUI下拉列表点击事件的使用方法,具有一定的参考价值,感兴趣的小伙伴们可以参考一下...2017-05-22
  • Vue多选列表组件深入详解

    这篇文章主要介绍了Vue多选列表组件深入详解,这个是vue的基本组件,有需要的同学可以研究下...2021-03-03
  • C#事件实例详解

    这篇文章主要介绍了C#事件实例详解的相关资料,需要的朋友可以参考下...2020-06-25
  • jQuery Mobile 触摸事件实例

    这篇文章主要演示了5个jQuery Mobile 触摸事件实例,需要的朋友可以参考下。...2016-06-12
  • Bootstrap进度条组件知识详解

    在网页中,经常见到进度条效果,那么这些个性的进度条组件效果是怎么实现的呢,下面脚本之家小编给大家分享Bootstrap进度条组件知识详解,感兴趣的朋友要求学习吧...2016-05-04
  • Vue父子组件传值的一些坑

    这篇文章主要介绍了Vue父子组件传值的一些坑,帮助大家更好的理解和使用vue父子组件,感兴趣的朋友可以了解下...2020-09-16
  • 使用Angular CDK实现一个Service弹出Toast组件功能

    本文主要写用cdk实现一个简单的Toast组件,使用的是cdk中的overlay模块,需要手动安装环境,具体安装方法及相关实现代码跟随小编一起看看吧...2021-07-28
  • vue递归实现自定义tree组件

    这篇文章主要为大家详细介绍了vue递归实现自定义tree组件,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下...2021-08-20
  • Mysql索引会失效的几种情况分析

    索引并不是时时都会生效的,比如以下几种情况,将导致索引失效: 1.如果条件中有or,即使其中有条件带索引也不会使用(这也是为什么尽量少用or的原因)  注意:要想使用or,又想让索引生效,只能将or条件中的每个列都加上索引 ...2014-06-07
  • jQuery绑定事件监听bind和移除事件监听unbind用法实例详解

    这篇文章主要介绍了jQuery绑定事件监听bind和移除事件监听unbind用法,结合实例形式详细分析了绑定事件监听bind和移除事件监听unbind的具体使用技巧与相关注意事项,需要的朋友可以参考下...2016-01-21
  • 详解C#中委托,事件与回调函数讲解

    这篇文章主要介绍了详解C#中委托,事件与回调函数讲解,小编觉得挺不错的,现在就分享给大家,也给大家做个参考。...2020-06-25