关闭

Laravel 框架的事件机制

603人阅读 评论(1) 收藏 举报
分类:

Laravel 框架的事件处理机制是通过类EventServiceProvider来实现的.

建立事件

首先我需要将自己的事件和监听者注册到app\Providers目录下的EventServiceProvider类中的$listen数组中


然后运行php  artisan event:generate 命令会自动生成相应的事件类和监听者类。然后在相应的类中编写事件的逻辑和监听者的逻辑。调用事件可以使用  Event:: fire(new App\Events\TestEvent()) .这就是调用事件的基本步骤。具体请参考官方文档。

事件触发前

在服务提供者中,一般有register和boot方法,而boot方法一般在框架中已经注册完所有的服务提供者之后运行。而app\Providers目录下的EventServiceProvider类中的boot方法继承父类的boot方法。于是我们查看父类的boot方法如下:

 public function boot()
    {
        foreach ($this->listens() as $event => $listeners) {
            foreach ($listeners as $listener) {
                Event::listen($event, $listener);
            }
        }

        foreach ($this->subscribe as $subscriber) {
            Event::subscribe($subscriber);
        }
    }
其实就是获取$listens属性数组并且进行遍历,将数组中的事件(键)和事件监听者(数组的键值)进行绑定。为了查看绑定的过程,我 们又要查看Event::listen  这个方法。由于调用的是facade,我们根据facade模式寻找到对应的类(facade模式原理请查看博文:http://blog.csdn.net/qq_16877261/article/details/77530081)  \Illuminate\Events\Dispatcher找到listen方法如下:

 public function listen($events, $listener)
    {
        foreach ((array)$events as $event) {
            if (Str::contains($event, '*')) {
                $this->setupWildcardListen($event, $listener);
            } else {
                $this->listeners[$event][] = $this->makeListener($listener);
            }
        }
    }
在这里我就不研究通配符形式的事件与事件监听者的绑定。于是其实代码通过
 $this->listeners[$event][] = $this->makeListener($listener);
进行了绑定。我查看makeListener 方法如下:

 public function makeListener($listener, $wildcard = false)
    {
        if (is_string($listener)) {
            return $this->createClassListener($listener, $wildcard);
        }

        return function ($event, $payload) use ($listener, $wildcard) {
            if ($wildcard) {
                return $listener($event, $payload);
            } else {
                return $listener(...array_values($payload));
            }
        };
    }
由于我们注册的事件监听者是字符串,代码运行到这一步。
 return $this->createClassListener($listener, $wildcard);
于是跟踪函数代码如下:

 public function createClassListener($listener, $wildcard = false)
    {
        //将监听者封装成闭包
        return function ($event, $payload) use ($listener, $wildcard) {
            if ($wildcard) {
                return call_user_func($this->createClassCallable($listener), $event, $payload);
            } else {
                return call_user_func_array(
                    $this->createClassCallable($listener), $payload
                );
            }
        };
    }
在这一步,函数将事件监听者封装成闭包的形式。在闭包里面通过如下代码实现了调用事件监听者的handle方法,以便在触发事件后调用闭包从而执行该方法。

 return call_user_func_array(
                    $this->createClassCallable($listener), $payload
                );
$this->createClassCallable($listener)
而这一步返回一个数组 [$listener,'handle'],通过call_user_func_array 函数实现了上述过程。

总结:在boot方法中实现事件监听者的注册与事件的绑定,而在注册与绑定过程中,将会封装一个闭包,并且在闭包中实现调用事件监听者类中的handle方法。

事件触发

事件触发采用如下形式:

  Event::fire(new TestEvent());
在调用fire方法前,会实例化事件类,进行事件的逻辑操作。同样的我们在\Illuminate\Events\Dispatcher找到fire方法如下:

 public function fire($event, $payload = [], $halt = false)
    {
        return $this->dispatch($event, $payload, $halt);
    }
其实fire方法调用的还是dispatch方法。
 public function dispatch($event, $payload = [], $halt = false)
    {
        // When the given "event" is actually an object we will assume it is an event
        // object and use the class as the event name and this event itself as the
        // payload to the handler, which makes object based events quite simple.
        list($event, $payload) = $this->parseEventAndPayload(
            $event, $payload
        );
// -----------------------------这部分涉及广播系统,以后会详细讲解,这里就不讲解了。
        if ($this->shouldBroadcast($payload)) {
            $this->broadcastEvent($payload[0]);
        }
//------------------------------
        $responses = [];

        foreach ($this->getListeners($event) as $listener) {
            //$listener 是一个闭包
            $response = $listener($event, $payload);
            // If a response is returned from the listener and event halting is enabled
            // we will just return this response, and not call the rest of the event
            // listeners. Otherwise we will add the response on the response list.
            if (!is_null($response) && $halt) {
                return $response;
            }

            // If a boolean false is returned from a listener, we will stop propagating
            // the event to any further listeners down in the chain, else we keep on
            // looping through the listeners and firing every one in our sequence.
            if ($response === false) {
                break;
            }

            $responses[] = $response;
        }

        return $halt ? null : $responses;
    }
由于传进来的参数是实例化后的event 对象,所以在dispatch方法中首先通过parseEventAndPayload方法解析出字符串类型的事件名称和数组类型的(元素为事件对象)$payload 。然后根据事件名称 从之前保存过的
$this->listeners
数组中解析出监听者的闭包,然后通过闭包调用监听者类的handle方法。至此,事件机制原理讲解完了。


2
0
查看评论

laravel框架与其他框架的对比

优点:1、代码比较明白易懂,跟英语句子差不多,关键词就是函数,举个例子,获取数据库中某个表的所有数据:$article=new Article; $articles=$article->all(); //这样就得到了articles表所有记录的所有字段; $count = $article-...
  • zhezhebie
  • zhezhebie
  • 2017-05-08 10:21
  • 1215

Laravel框架的体系结构

Laravel被称为“全栈”式框架,因为它能够处理从网络服务到数据库管理、HTML生成的一切事情,垂直集成的web开发环境给开发者提供了更好的体验。 开发人员可以通过命令行工具,生成和管理Laravel项目环境。Laravel附带了一个名为Artisan的优秀的命令行工具,它提供了一些开发过程中有...
  • u010366748
  • u010366748
  • 2015-10-28 17:33
  • 1722

Laravel 5.1 定义事件、事件监听器以及触发事件实例教程

今天我们开始讲Laravel的事件,事件无处不在,比如用户登录、购买商品、搜索、查看文章,等等,都是事件,有了事件,就有事件监听器,事件监听器监听到事件发生后会执行一些操作,Laravel使用观察者模式来实现这种监听机制。本节我们通过一个简单的示例来讲述在Laravel中如何创建事件类、事件对应的监...
  • juner_ge
  • juner_ge
  • 2016-06-27 10:31
  • 838

Laravel5框架的搭建

刚尝试在Windows下搭建Laravel框架: 步骤如下: 1:搭建laravel框架首先要安装composer   地址:http://getcomposer.org/ 安装包地址点击打开链接。下一步,指定正确的 php.exe 文件地位(如下图)。 开启 php_open...
  • xiaoxiaohui520134
  • xiaoxiaohui520134
  • 2016-05-06 15:32
  • 1108

laravel框架详解

laravel框架是现在php框架中十分流行的框架 1、概念 Laravel是一个有着美好前景的年轻框架,它的社区充满着活力,同时提供了完整而清晰的文档,而且为快速、安全地开发现代应用提供了必要的功能。 2011年,Taylor Otwell首次将Laravel带给这个世界,彼时,Laravel就...
  • woshihaiyong168
  • woshihaiyong168
  • 2016-11-17 21:09
  • 1622

laravel框架目录结构

就如你看到这样,laravel下面只包含了4个文件夹,这4个文件夹下面有一些子文件夹,这种丰富的子文件夹在第一次看到是不是有压力?我会逐个介绍。我们大部分的开发工作都会在app/文件夹下面进行。   下面是各个文件夹和文件的基本介绍: 顶级文件夹 作用 ...
  • will5451
  • will5451
  • 2016-09-08 20:00
  • 3104

lavarel框架在中国的发展前景

我来说两点 lavarel作为一个5.4版本出现的新框架,在一个php版本环境低于5.6以前的服务器是运行不起来的,因为里面全部都是用的新语法,而国内的项目大部分都是以前的老的项目,而且作为一个运行起来的项目来说,重新推倒然后用laravel来做,是非常非常的得不偿失的,典型的例子之一就是...
  • lzq_csdn_th
  • lzq_csdn_th
  • 2016-07-19 10:57
  • 1125

为什么 Laravel 5 这么好一个框架国内开发者都不去用?

为什么 Laravel 5 这么好一个框架,国人都不去用? 为什么 Laravel 5 这么好一个框架,国人都不去用? 为什么都去用那种垃圾的 ThinkPHP ? 国内的教程和资料,几乎没有。。 国外的教程资料都是海量的,书也是海量的。 我经过学习后,我发现lar...
  • English0523
  • English0523
  • 2017-02-15 14:11
  • 1112

Laravel 5.5框架 核心类Kernel

<?phpnamespace App\Http;use Illuminate\Foundation\Http\Kernel as HttpKernel;class Kernel extends HttpKernel { /** * The application's ...
  • github_38245606
  • github_38245606
  • 2017-12-23 15:23
  • 105

laravel 5.4 框架的搭建和使用

环境windowslaravel框架的下载主要靠composer,其他的版本和拓展必须满足:PHP版本 >= 5.6.4 PHP扩展:OpenSSL PHP扩展:PDO PHP扩展:Mbstring PHP扩展:Tokenizer PHP扩展:XML php -v 查看版本 php -m 查...
  • CSDN_GOON
  • CSDN_GOON
  • 2017-05-06 21:49
  • 1868
    个人资料
    • 访问:42545次
    • 积分:1195
    • 等级:
    • 排名:千里之外
    • 原创:74篇
    • 转载:33篇
    • 译文:1篇
    • 评论:22条
    文章分类
    最新评论