Summary
Looking at the title, I don't know what the author wants to say. Recently, when looking at Swoole, I encountered a decoupling problem in encapsulating the framework. Decoupling is not unfamiliar to everyone. This decoupling is a demo about listening events and heartbeat detection. Let's look directly at the problem.
Solutions
I want to add event listeners when Swoole starts, such as the registry in RPC, which services I start and provide similar scenarios, etc., but this is just an event listener, what if more? For example, when I receive a request, receive a message, close the connection, etc., you need to create a lot of time to listen, this time you may start all the events to register, and then see how the code is simple and rude implementation.
<?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(); #Actively Collect Existing Events Collect Listener Directory $this->collecEvent(); //timer swoole_timer_tick(3000, function () use ($reload) { if ($reload->reload()) { $this->server->reload(); //restart } }); Event::trigger('start', ['sss']); } /** * Collect events */ 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;#Configurable file if (class_exists($nameSpace)) { $obj = new $nameSpace; #Get the event name you defined and read the class document annotations using reflection $re = new \ReflectionClass($obj); if (strlen($re->getDocComment()) < 2) { throw new \Exception('Event names are not defined in accordance with the specification'); } else { preg_match("/@Listener\((.*)\)/i", $re->getDocComment(), $eventName); if (empty($eventName)) { throw new \Exception('Event names are not defined in accordance with the specification'); } #Registered events Event::register($eventName[1], [$obj, 'handle']); } } } } } ... }
- Call collecEvent method when Swoole is started
- ColecEvent is responsible for collecting, registering methods in specified directories and namespaces
- EVENT_PATH = APP_PATH.'/listener'
- Loop through all files in the directory
- Get the file name
- Splicing namespaces (namespaces can be placed in configuration files such as Config)
- class_exists checks for class existence
- ReflectionClass here uses the form of reflection and annotation to determine compliance.
- getDocComment() Gets the annotation content
- Regular /@Listener((*))/ I matches the events that need to be monitored
- Perform Event::register($event,$callback) for event registration
Next, look at the Event class:
class Event { public static $events = []; //Event registration /** * @param $event Event name * @param $callback event callbacks */ public static function register($event, $callback) { $event = strtolower($event);//Case insensitive if (!isset(self::$events[$event])) { self::$events[$event] = []; } self::$events[$event] = ['callback' => $callback]; } //Event triggering public static function trigger($event, $params = []) { $event = strtolower($event);//Case insensitive if (isset(self::$events[$event])) { call_user_func(self::$events[$event]['callback'], $params); return true; } return false; } }
- Event contains two static methods: event registration and event triggering
- Event registration implements putting said events into the $event attribute
- Event Trigger: Verify that the event exists and call_user_func() executes the callback function
Look again at how to declare an event file:
<?php namespace App\Listener; /** * Class StartListener * @package App\Listener * @Listener(start) */ class StartListener { public function handle($params) { go(function () {//Creating Ctrip Environment //Upgraded 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)); //Heart beat management swoole_timer_tick(3000, function () use ($cli) { if ($cli->errCode == 0) { $cli->push('11', WEBSOCKET_OPCODE_PING); } }); } }); } }
- We should inherit an interface class here. We must implement handle() method. We can implement it by ourselves.
- handle() method implements a function similar to notification registry registration service
- swoole_timer_tick() uses millisecond timer to process heartbeat
- Document annotations for reflex grabbing
/** * Class StartListener * @package App\Listener * @Listener(start) */
call
public function start() { ... #Actively Collect Existing Events Collect Listener Directory $this->collecEvent(); ... Event::trigger('start', ['sss']); }
Thanks for watching
Thank you for your patience. I hope it will be helpful to you. I also hope you can provide different opinions and find more effective ways to complete and learn together. Thank you.