看標題也不知道做者想要說些什麼,最近在看Swoole方面的內容,在封裝框架時遇到了一個關於解耦的問題,解耦你們並不陌生,此次的解耦是關於監聽事件和心跳檢測的一個demo,直接來看下問題吧。php
在Swoole啓動時我想加入一些事件監聽,好比RPC中的註冊中心,我啓動、提供了哪些服務相似的場景等等,可是這只是一種事件監聽,若是要多個呢?好比當我接收到請求以後、收到消息以後、鏈接關閉以後等等,你須要建立不少的時間監聽,這個時候你可能在啓動時候把全部事件都要註冊進去,接下來看下代碼是如何簡單粗暴的實現的。web
<?php namespace LoyaltyLu\Core; use LoyaltyLu\Core\Event\Event; use Swoole\Http\Server; class Http { ... public function start() { $reload = Reload::get_instance(); $reload->watch = [CONFIG_PATH, FRAME_PATH, APP_PATH]; $reload->md5Flag = $reload->getMd5(); #主動收集已有事件收集Listener目錄 $this->collecEvent(); //定時器 swoole_timer_tick(3000, function () use ($reload) { if ($reload->reload()) { $this->server->reload(); //重啓 } }); Event::trigger('start', ['sss']); } /** * 收集事件 */ public function collecEvent() { $files = glob(EVENT_PATH . "/*.php"); if (!empty($files)) { foreach ($files as $dir => $fileName) { include "{$fileName}"; $fileName = explode('/', $fileName); $className = explode('.', end($fileName))[0]; $nameSpace = 'App\\Listener\\' . $className;#可放入配置文件 if (class_exists($nameSpace)) { $obj = new $nameSpace; #獲得本身定義的事件名稱,利用反射讀取類文檔註釋 $re = new \ReflectionClass($obj); if (strlen($re->getDocComment()) < 2) { throw new \Exception('沒有按照規範定義事件名稱'); } else { preg_match("/@Listener\((.*)\)/i", $re->getDocComment(), $eventName); if (empty($eventName)) { throw new \Exception('沒有按照規範定義事件名稱'); } #註冊的事件 Event::register($eventName[1], [$obj, 'handle']); } } } } } ... }
EVENT_PATH = APP_PATH.'/listener'
class_exists
檢查類是否存在ReflectionClass
這裏用到了反射、註解的形式判斷是否符合getDocComment()
獲取註釋內容/@Listener\((.*)\)/i
匹配出須要監聽的所屬事件Event::register($event,$callback)
進行事件註冊接下來看下Event
類:json
class Event { public static $events = []; //事件註冊 /** * @param $event 事件名 * @param $callback 事件回調 */ public static function register($event, $callback) { $event = strtolower($event);//不區分大小寫 if (!isset(self::$events[$event])) { self::$events[$event] = []; } self::$events[$event] = ['callback' => $callback]; } //事件觸發 public static function trigger($event, $params = []) { $event = strtolower($event);//不區分大小寫 if (isset(self::$events[$event])) { call_user_func(self::$events[$event]['callback'], $params); return true; } return false; } }
Event
當中包含2個靜態方法:事件註冊、事件觸發call_user_func()
執行回調函數再看下如何聲明一個事件的文件:swoole
<?php namespace App\Listener; /** * Class StartListener * @package App\Listener * @Listener(start) */ class StartListener { public function handle($params) { go(function () {//建立攜程環境 //升級的websockt $cli = new \Swoole\Coroutine\Http\Client('127.0.0.1', 9600); $ret = $cli->upgrade('/'); if ($ret) { // Config::get() $data = [ 'method' => 'register', 'serviceName' => "Server", 'ip' => '0.0.0.0', 'port' => 9800, ]; $cli->push(json_encode($data)); //心跳處理 swoole_timer_tick(3000, function () use ($cli) { if ($cli->errCode == 0) { $cli->push('11', WEBSOCKET_OPCODE_PING); } }); } }); } }
handle()
方法,你們能夠本身實現下handle()
方法這裏實現了一個相似通知註冊中心註冊服務的功能swoole_timer_tick()
利用毫秒級定時器處理心跳/** * Class StartListener * @package App\Listener * @Listener(start) */
public function start() { ... #主動收集已有事件收集Listener目錄 $this->collecEvent(); ... Event::trigger('start', ['sss']); }
謝謝你們耐心觀看,但願對您有所幫助,也但願你們提供下不一樣的意見,找到更有效的方式來完成,共同窗習,謝謝!框架