[ Laravel 5.2 文档 ] 服务 -- 事件
1、简介
Laravel事件提供了简单的观察者模式实现,允许你订阅和监听应用中的事件。事件类通常存放在 app/Events目录,监听器存放在 app/Listeners。
2、注册事件/监听器
Laravel 自带的 EventServiceProvider为事件注册提供了方便之所。其中的 listen属性包含了事件(键)和对应监听器(值)数组。如果应用需要,你可以添加多个事件到该数组。例如,让我们添加 PodcastWasPurchased事件:
/** * 事件监听器映射 * * @var array */protected $listen = [ 'App\Events\PodcastWasPurchased' => [ 'App\Listeners\EmailPurchaseConfirmation', ],];
2.1 生成事件/监听器类
当然,手动为每个事件和监听器创建文件是很笨重的,取而代之地,我们可见简单添加监听器和事件到 EventServiceProvider然后使用 event:generate命令。该命令将会生成罗列在 EventServiceProvider中的所有事件和监听器。当然,已存在的事件和监听器不会被创建:
php artisan event:generate
2.2 手动注册事件
一般我们需要将事件注册到 EventServiceProvider的 $listen数组,此外,我们还可以使用 Event门面或者 Illuminate\Contracts\Events\Dispatcher契约的具体实现类作为事件分发器手动注册事件:
/** * Register any other events for your application. * * @param \Illuminate\Contracts\Events\Dispatcher $events * @return void */public function boot(DispatcherContract $events){ parent::boot($events); $events->listen('event.name', function ($foo, $bar) { // });}
使用通配符作为事件监听器
你还可以使用通配符*来注册监听器,从而允许你通过同一个监听器捕获多个事件。通配符监听器接收整个事件数据数组作为参数:
$events->listen('event.*', function (array $data) { //});
3、定义事件
事件类是一个处理与事件相关的简单数据容器,例如,假设我们生成的 PodcastWasPurchased事件接收一个Eloquent ORM对象:
<?phpnamespace App\Events;use App\Podcast;use App\Events\Event;use Illuminate\Queue\SerializesModels;class PodcastWasPurchased extends Event{ use SerializesModels; public $podcast; /** * 创建新的事件实例 * * @param Podcast $podcast * @return void */ public function __construct(Podcast $podcast) { $this->podcast = $podcast; }}
正如你所看到的,该事件类不包含任何特定逻辑,只是一个存放被购买的 Podcast对象的容器,如果事件对象被序列化的话,事件使用的 SerializesModelstrait 将会使用 PHP 的 serialize函数序列化所有 Eloquent 模型。
4、定义监听器
接下来,让我们看看我们的示例事件的监听器,事件监听器在 handle方法中接收事件实例, event:generate命令将会自动在 handle方法中导入合适的事件类和类型提示事件。在 handle方法内,你可以执行任何需要的逻辑以响应事件。
<?phpnamespace App\Listeners;use App\Events\PodcastWasPurchased;use Illuminate\Queue\InteractsWithQueue;use Illuminate\Contracts\Queue\ShouldQueue;class EmailPurchaseConfirmation{ /** * 创建事件监听器 * * @return void */ public function __construct() { // } /** * 处理事件 * * @param PodcastWasPurchased $event * @return void */ public function handle(PodcastWasPurchased $event) { // Access the podcast using $event->podcast... }}
你的事件监听器还可以在构造器中类型提示任何需要的依赖,所有事件监听器通过服务容器解析,所以依赖会自动注入:
use Illuminate\Contracts\Mail\Mailer;public function __construct(Mailer $mailer){ $this->mailer = $mailer;}
停止事件继续往下传播
有时候,你希望停止事件被传播到其它监听器,你可以通过从监听器的 handle方法中返回 false来实现。
事件监听器队列
需要将事件监听器放到队列?没有比这更简单的了,只需要让监听器类实现 ShouldQueue接口即可,通过 Artisan 命令 event:generate生成的监听器类已经将接口导入当前命名空间,所有你可以立即拿来使用:
<?phpnamespace App\Listeners;use App\Events\PodcastWasPurchased;use Illuminate\Queue\InteractsWithQueue;use Illuminate\Contracts\Queue\ShouldQueue;class EmailPurchaseConfirmation implements ShouldQueue{ //}
就是这么简单,当监听器被事件调用,将会使用 Laravel 的队列系统通过队列分发器自动队列化。如果通过队列执行监听器的时候没有抛出任何异常,队列任务在执行完成后被自动删除。
手动访问队列
如果你需要手动访问底层队列任务的 delete和 release方法,在生成的监听器中默认导入的 Illuminate\Queue\InteractsWithQueuetrait 提供了访问这两个方法的权限:
<?phpnamespace App\Listeners;use App\Events\PodcastWasPurchased;use Illuminate\Queue\InteractsWithQueue;use Illuminate\Contracts\Queue\ShouldQueue;class EmailPurchaseConfirmation implements ShouldQueue{ use InteractsWithQueue; public function handle(PodcastWasPurchased $event) { if (true) { $this->release(30); } }}
5、触发事件
要触发一个事件,可以使用 Event门面,传递一个事件实例到 fire方法, fire方法会分发事件到所有监听器:
<?phpnamespace App\Http\Controllers;use Event;use App\Podcast;use App\Events\PodcastWasPurchased;use App\Http\Controllers\Controller;class UserController extends Controller{ /** * 显示指定用户属性 * * @param int $userId * @param int $podcastId * @return Response */ public function purchasePodcast($userId, $podcastId) { $podcast = Podcast::findOrFail($podcastId); // Purchase podcast logic... Event::fire(new PodcastWasPurchased($podcast)); }}
此外,你还可以使用全局的辅助函数 event来触发事件:
event(new PodcastWasPurchased($podcast));
6、 广播事件
在很多现代 Web 应用中,Web 套接字被用于实现实时更新的用户接口。当一些数据在服务器上被更新,通常一条消息通过 websocket 连接被发送给客户端处理。
为帮助你构建这样的应用,Laravel 让通过 websocket 连接广播事件变得简单。广播 Laravel 事件允许你在服务端和客户端 JavaScript 框架之间共享同一事件名。
6.1 配置
所有的事件广播配置选项都存放在 config/broadcasting.php配置文件中。Laravel 支持多种广播驱动: Pusher、Redis以及一个服务于本地开发和调试的日志驱动。每一个驱动都有一个配置示例。
广播预备知识
事件广播需要以下两个依赖:
- Pusher: pusher/pusher-php-server ~2.0
- Redis: predis/predis ~1.0
队列预备知识
在开始介绍广播事件之前,还需要配置并运行一个队列监听器。所有事件广播都通过队列任务来完成以便应用的响应时间不受影响。
6.2 将事件标记为广播
要告诉 Laravel 给定事件应该被广播,需要在事件类上实现 Illuminate\Contracts\Broadcasting\ShouldBroadcast接口。 ShouldBroadcast接口要求你实现一个方法: broadcastOn。该方法应该返回事件广播“频道”名称数组:
<?phpnamespace App\Events;use App\User;use App\Events\Event;use Illuminate\Queue\SerializesModels;use Illuminate\Contracts\Broadcasting\ShouldBroadcast;class ServerCreated extends Event implements ShouldBroadcast{ use SerializesModels; public $user; /** * 创建新的事件实例 * * @return void */ public function __construct(User $user) { $this->user = $user; } /** * 获取事件广播频道 * * @return array */ public function broadcastOn() { return ['user.'.$this->user->id]; }}
然后,你只需要和正常一样触发该事件,事件被触发后,一个队列任务将通过指定广播驱动自动广播该事件。
6.3 广播数据
如果某个事件被广播,其所有的 public属性都会按照事件负载自动序列化和广播,从而允许你从 JavaScript 中访问所有 public数据,因此,举个例子,如果你的事件有一个单独的包含 Eloquent 模型的 $user属性,广播负载定义如下:
{ "user": { "id": 1, "name": "Jonathan Banks" ... }}
然而,如果你希望对广播负载有更加细粒度的控制,可以添加 broadcastWith方法到事件,该方法应该返回你想要通过事件广播的数组数据:
/** * 获取广播数据 * * @return array */public function broadcastWith(){ return ['user' => $this->user->id];}
6.4 自定义事件广播
自定义事件名
默认情况下,广播事件名就是事件类名,因此,如果事件的类名是 App\Events\ServerCreated,对应的广播事件名就是 App\Events\ServerCreated,你可以通过事件类上的 broadcastAs方法自定义广播事件名:
/** * 获取广播事件名称 * * @return string */public function broadcastAs(){ return 'app.server-created';}
自定义队列
默认情况下,每个被广播的事件都位于配置文件 queue.php中定义的默认队列连接中的默认队列中,你可以通过事件类的 onQueue方法自定义广播事件的队列名称。该方法会返回你期望使用的队列名:
/** * 设置事件所在队列的名称 * * @return string */public function onQueue(){ return 'your-queue-name';}
6.5 消费事件广播
Pusher
你可以通过 Pusher 的 JavaScript SDK 方便地使用 Pusher驱动消费事件广播。例如,让我们从之前的例子中消费 App\Events\ServerCreated事件:
this.pusher = new Pusher('pusher-key');this.pusherChannel = this.pusher.subscribe('user.' + USER_ID);this.pusherChannel.bind('App\\Events\\ServerCreated', function(message) { console.log(message.user);});
Redis
如果你在使用 Redis 广播,你将需要编写自己的 Redis pub/sub 消费者来接收消息并使用自己选择的 websocket 技术将其进行广播。例如,你可以选择使用 Node 编写的流行的 Socket.io库。
使用 Node 库 socket.io和 ioredis,你可以快速编写事件广播发布所有广播事件:
var app = require('http').createServer(handler);var io = require('socket.io')(app);var Redis = require('ioredis');var redis = new Redis();app.listen(6001, function() { console.log('Server is running!');});function handler(req, res) { res.writeHead(200); res.end('');}io.on('connection', function(socket) { //});redis.psubscribe('*', function(err, count) { //});redis.on('pmessage', function(subscribed, channel, message) { message = JSON.parse(message); io.emit(channel + ':' + message.event, message.data);});
7、事件订阅者
事件订阅者是指那些在类本身中订阅到多个事件的类,从而允许你在单个类中定义一些事件处理器。订阅者应该定义一个 subscribe方法,该方法中传入一个事件分发器实例:
<?phpnamespace App\Listeners;class UserEventListener{ /** * 处理用户登录事件 */ public function onUserLogin($event) {} /** * 处理用户退出事件 */ public function onUserLogout($event) {} /** * 为订阅者注册监听器 * * @param Illuminate\Events\Dispatcher $events * @return array */ public function subscribe($events) { $events->listen( 'App\Events\UserLoggedIn', 'App\Listeners\UserEventListener@onUserLogin' ); $events->listen( 'App\Events\UserLoggedOut', 'App\Listeners\UserEventListener@onUserLogout' ); }}
注册一个事件订阅者
订阅者被定义后,可以通过事件分发器进行注册,你可以使用 EventServiceProvider上的 $subcribe属性来注册订阅者。例如,让我们添加 UserEventListener:
<?phpnamespace App\Providers;use Illuminate\Contracts\Events\Dispatcher as DispatcherContract;use Illuminate\Foundation\Support\Providers\EventServiceProvider as ServiceProvider;class EventServiceProvider extends ServiceProvider{ /** * 事件监听器映射数组 * * @var array */ protected $listen = [ // ]; /** * 要注册的订阅者 * * @var array */ protected $subscribe = [ 'App\Listeners\UserEventListener', ];}

熱AI工具

Undresser.AI Undress
人工智慧驅動的應用程序,用於創建逼真的裸體照片

AI Clothes Remover
用於從照片中去除衣服的線上人工智慧工具。

Undress AI Tool
免費脫衣圖片

Clothoff.io
AI脫衣器

Video Face Swap
使用我們完全免費的人工智慧換臉工具,輕鬆在任何影片中換臉!

熱門文章

熱工具

記事本++7.3.1
好用且免費的程式碼編輯器

SublimeText3漢化版
中文版,非常好用

禪工作室 13.0.1
強大的PHP整合開發環境

Dreamweaver CS6
視覺化網頁開發工具

SublimeText3 Mac版
神級程式碼編輯軟體(SublimeText3)

PHP和Python各有優勢,選擇依據項目需求。 1.PHP適合web開發,尤其快速開發和維護網站。 2.Python適用於數據科學、機器學習和人工智能,語法簡潔,適合初學者。

在PHP中,應使用password_hash和password_verify函數實現安全的密碼哈希處理,不應使用MD5或SHA1。1)password_hash生成包含鹽值的哈希,增強安全性。 2)password_verify驗證密碼,通過比較哈希值確保安全。 3)MD5和SHA1易受攻擊且缺乏鹽值,不適合現代密碼安全。

PHP在電子商務、內容管理系統和API開發中廣泛應用。 1)電子商務:用於購物車功能和支付處理。 2)內容管理系統:用於動態內容生成和用戶管理。 3)API開發:用於RESTfulAPI開發和API安全性。通過性能優化和最佳實踐,PHP應用的效率和可維護性得以提升。

PHP通過$\_FILES變量處理文件上傳,確保安全性的方法包括:1.檢查上傳錯誤,2.驗證文件類型和大小,3.防止文件覆蓋,4.移動文件到永久存儲位置。

PHP是一種廣泛應用於服務器端的腳本語言,特別適合web開發。 1.PHP可以嵌入HTML,處理HTTP請求和響應,支持多種數據庫。 2.PHP用於生成動態網頁內容,處理表單數據,訪問數據庫等,具有強大的社區支持和開源資源。 3.PHP是解釋型語言,執行過程包括詞法分析、語法分析、編譯和執行。 4.PHP可以與MySQL結合用於用戶註冊系統等高級應用。 5.調試PHP時,可使用error_reporting()和var_dump()等函數。 6.優化PHP代碼可通過緩存機制、優化數據庫查詢和使用內置函數。 7

PHP仍然具有活力,其在現代編程領域中依然佔據重要地位。 1)PHP的簡單易學和強大社區支持使其在Web開發中廣泛應用;2)其靈活性和穩定性使其在處理Web表單、數據庫操作和文件處理等方面表現出色;3)PHP不斷進化和優化,適用於初學者和經驗豐富的開發者。

PHP類型提示提升代碼質量和可讀性。 1)標量類型提示:自PHP7.0起,允許在函數參數中指定基本數據類型,如int、float等。 2)返回類型提示:確保函數返回值類型的一致性。 3)聯合類型提示:自PHP8.0起,允許在函數參數或返回值中指定多個類型。 4)可空類型提示:允許包含null值,處理可能返回空值的函數。

PHP和Python各有優劣,選擇取決於項目需求和個人偏好。 1.PHP適合快速開發和維護大型Web應用。 2.Python在數據科學和機器學習領域佔據主導地位。
