walkor 3 yıl önce
ebeveyn
işleme
0122a8701c
43 değiştirilmiş dosya ile 2058 ekleme ve 2556 silme
  1. 0 69
      Autoloader.php
  2. 0 191
      Events/Ev.php
  3. 0 215
      Events/Event.php
  4. 0 107
      Events/EventInterface.php
  5. 0 225
      Events/Libevent.php
  6. 0 264
      Events/React/Base.php
  7. 0 27
      Events/React/ExtEventLoop.php
  8. 0 27
      Events/React/ExtLibEventLoop.php
  9. 0 26
      Events/React/StreamSelectLoop.php
  10. 0 341
      Events/Select.php
  11. 0 230
      Events/Swoole.php
  12. 0 44
      Lib/Constants.php
  13. 0 22
      Lib/Timer.php
  14. 9 47
      README.md
  15. 2 2
      composer.json
  16. 46 51
      src/Connection/AsyncTcpConnection.php
  17. 20 26
      src/Connection/AsyncUdpConnection.php
  18. 28 6
      src/Connection/ConnectionInterface.php
  19. 126 104
      src/Connection/TcpConnection.php
  20. 7 6
      src/Connection/UdpConnection.php
  21. 203 0
      src/Events/Ev.php
  22. 255 0
      src/Events/Event.php
  23. 111 0
      src/Events/EventInterface.php
  24. 240 0
      src/Events/Revolt.php
  25. 375 0
      src/Events/Select.php
  26. 200 0
      src/Events/Swoole.php
  27. 2 1
      src/Protocols/Frame.php
  28. 13 14
      src/Protocols/Http.php
  29. 2 1
      src/Protocols/Http/Chunk.php
  30. 74 39
      src/Protocols/Http/Request.php
  31. 44 27
      src/Protocols/Http/Response.php
  32. 1 0
      src/Protocols/Http/ServerSentEvents.php
  33. 5 4
      src/Protocols/Http/Session.php
  34. 18 12
      src/Protocols/Http/Session/FileSessionHandler.php
  35. 1 0
      src/Protocols/Http/Session/RedisSessionHandler.php
  36. 4 3
      src/Protocols/Http/Session/SessionHandlerInterface.php
  37. 0 0
      src/Protocols/Http/mime.types
  38. 5 4
      src/Protocols/ProtocolInterface.php
  39. 2 1
      src/Protocols/Text.php
  40. 46 114
      src/Protocols/Websocket.php
  41. 52 61
      src/Protocols/Ws.php
  42. 29 21
      src/Timer.php
  43. 138 224
      src/Worker.php

+ 0 - 69
Autoloader.php

@@ -1,69 +0,0 @@
-<?php
-/**
- * This file is part of workerman.
- *
- * Licensed under The MIT License
- * For full copyright and license information, please see the MIT-LICENSE.txt
- * Redistributions of files must retain the above copyright notice.
- *
- * @author    walkor<walkor@workerman.net>
- * @copyright walkor<walkor@workerman.net>
- * @link      http://www.workerman.net/
- * @license   http://www.opensource.org/licenses/mit-license.php MIT License
- */
-namespace Workerman;
-
-/**
- * Autoload.
- */
-class Autoloader
-{
-    /**
-     * Autoload root path.
-     *
-     * @var string
-     */
-    protected static $_autoloadRootPath = '';
-
-    /**
-     * Set autoload root path.
-     *
-     * @param string $root_path
-     * @return void
-     */
-    public static function setRootPath($root_path)
-    {
-        self::$_autoloadRootPath = $root_path;
-    }
-
-    /**
-     * Load files by namespace.
-     *
-     * @param string $name
-     * @return boolean
-     */
-    public static function loadByNamespace($name)
-    {
-        $class_path = \str_replace('\\', \DIRECTORY_SEPARATOR, $name);
-        if (\strpos($name, 'Workerman\\') === 0) {
-            $class_file = __DIR__ . \substr($class_path, \strlen('Workerman')) . '.php';
-        } else {
-            if (self::$_autoloadRootPath) {
-                $class_file = self::$_autoloadRootPath . \DIRECTORY_SEPARATOR . $class_path . '.php';
-            }
-            if (empty($class_file) || !\is_file($class_file)) {
-                $class_file = __DIR__ . \DIRECTORY_SEPARATOR . '..' . \DIRECTORY_SEPARATOR . "$class_path.php";
-            }
-        }
-
-        if (\is_file($class_file)) {
-            require_once($class_file);
-            if (\class_exists($name, false)) {
-                return true;
-            }
-        }
-        return false;
-    }
-}
-
-\spl_autoload_register('\Workerman\Autoloader::loadByNamespace');

+ 0 - 191
Events/Ev.php

@@ -1,191 +0,0 @@
-<?php
-/**
- * This file is part of workerman.
- *
- * Licensed under The MIT License
- * For full copyright and license information, please see the MIT-LICENSE.txt
- * Redistributions of files must retain the above copyright notice.
- *
- * @author  有个鬼<42765633@qq.com>
- * @link    http://www.workerman.net/
- * @license http://www.opensource.org/licenses/mit-license.php MIT License
- */
-namespace Workerman\Events;
-
-use Workerman\Worker;
-use \EvWatcher;
-
-/**
- * ev eventloop
- */
-class Ev implements EventInterface
-{
-    /**
-     * All listeners for read/write event.
-     *
-     * @var array
-     */
-    protected $_allEvents = array();
-
-    /**
-     * Event listeners of signal.
-     *
-     * @var array
-     */
-    protected $_eventSignal = array();
-
-    /**
-     * All timer event listeners.
-     * [func, args, event, flag, time_interval]
-     *
-     * @var array
-     */
-    protected $_eventTimer = array();
-
-    /**
-     * Timer id.
-     *
-     * @var int
-     */
-    protected static $_timerId = 1;
-
-    /**
-     * Add a timer.
-     * {@inheritdoc}
-     */
-    public function add($fd, $flag, $func, $args = null)
-    {
-        $callback = function ($event, $socket) use ($fd, $func) {
-            try {
-                \call_user_func($func, $fd);
-            } catch (\Exception $e) {
-                Worker::stopAll(250, $e);
-            } catch (\Error $e) {
-                Worker::stopAll(250, $e);
-            }
-        };
-        switch ($flag) {
-            case self::EV_SIGNAL:
-                $event                   = new \EvSignal($fd, $callback);
-                $this->_eventSignal[$fd] = $event;
-                return true;
-            case self::EV_TIMER:
-            case self::EV_TIMER_ONCE:
-                $repeat                             = $flag === self::EV_TIMER_ONCE ? 0 : $fd;
-                $param                              = array($func, (array)$args, $flag, $fd, self::$_timerId);
-                $event                              = new \EvTimer($fd, $repeat, array($this, 'timerCallback'), $param);
-                $this->_eventTimer[self::$_timerId] = $event;
-                return self::$_timerId++;
-            default :
-                $fd_key                           = (int)$fd;
-                $real_flag                        = $flag === self::EV_READ ? \Ev::READ : \Ev::WRITE;
-                $event                            = new \EvIo($fd, $real_flag, $callback);
-                $this->_allEvents[$fd_key][$flag] = $event;
-                return true;
-        }
-
-    }
-
-    /**
-     * Remove a timer.
-     * {@inheritdoc}
-     */
-    public function del($fd, $flag)
-    {
-        switch ($flag) {
-            case self::EV_READ:
-            case self::EV_WRITE:
-                $fd_key = (int)$fd;
-                if (isset($this->_allEvents[$fd_key][$flag])) {
-                    $this->_allEvents[$fd_key][$flag]->stop();
-                    unset($this->_allEvents[$fd_key][$flag]);
-                }
-                if (empty($this->_allEvents[$fd_key])) {
-                    unset($this->_allEvents[$fd_key]);
-                }
-                break;
-            case  self::EV_SIGNAL:
-                $fd_key = (int)$fd;
-                if (isset($this->_eventSignal[$fd_key])) {
-                    $this->_eventSignal[$fd_key]->stop();
-                    unset($this->_eventSignal[$fd_key]);
-                }
-                break;
-            case self::EV_TIMER:
-            case self::EV_TIMER_ONCE:
-                if (isset($this->_eventTimer[$fd])) {
-                    $this->_eventTimer[$fd]->stop();
-                    unset($this->_eventTimer[$fd]);
-                }
-                break;
-        }
-        return true;
-    }
-
-    /**
-     * Timer callback.
-     *
-     * @param EvWatcher $event
-     */
-    public function timerCallback(EvWatcher $event)
-    {
-        $param    = $event->data;
-        $timer_id = $param[4];
-        if ($param[2] === self::EV_TIMER_ONCE) {
-            $this->_eventTimer[$timer_id]->stop();
-            unset($this->_eventTimer[$timer_id]);
-        }
-        try {
-            \call_user_func_array($param[0], $param[1]);
-        } catch (\Exception $e) {
-            Worker::stopAll(250, $e);
-        } catch (\Error $e) {
-            Worker::stopAll(250, $e);
-        }
-    }
-
-    /**
-     * Remove all timers.
-     *
-     * @return void
-     */
-    public function clearAllTimer()
-    {
-        foreach ($this->_eventTimer as $event) {
-            $event->stop();
-        }
-        $this->_eventTimer = array();
-    }
-
-    /**
-     * Main loop.
-     *
-     * @see EventInterface::loop()
-     */
-    public function loop()
-    {
-        \Ev::run();
-    }
-
-    /**
-     * Destroy loop.
-     *
-     * @return void
-     */
-    public function destroy()
-    {
-        foreach ($this->_allEvents as $event) {
-            $event->stop();
-        }
-    }
-
-    /**
-     * Get timer count.
-     *
-     * @return integer
-     */
-    public function getTimerCount()
-    {
-        return \count($this->_eventTimer);
-    }
-}

+ 0 - 215
Events/Event.php

@@ -1,215 +0,0 @@
-<?php 
-/**
- * This file is part of workerman.
- *
- * Licensed under The MIT License
- * For full copyright and license information, please see the MIT-LICENSE.txt
- * Redistributions of files must retain the above copyright notice.
- *
- * @author    有个鬼<42765633@qq.com>
- * @copyright 有个鬼<42765633@qq.com>
- * @link      http://www.workerman.net/
- * @license   http://www.opensource.org/licenses/mit-license.php MIT License
- */
-namespace Workerman\Events;
-
-use Workerman\Worker;
-
-/**
- * libevent eventloop
- */
-class Event implements EventInterface
-{
-    /**
-     * Event base.
-     * @var object
-     */
-    protected $_eventBase = null;
-    
-    /**
-     * All listeners for read/write event.
-     * @var array
-     */
-    protected $_allEvents = array();
-    
-    /**
-     * Event listeners of signal.
-     * @var array
-     */
-    protected $_eventSignal = array();
-    
-    /**
-     * All timer event listeners.
-     * [func, args, event, flag, time_interval]
-     * @var array
-     */
-    protected $_eventTimer = array();
-
-    /**
-     * Timer id.
-     * @var int
-     */
-    protected static $_timerId = 1;
-    
-    /**
-     * construct
-     * @return void
-     */
-    public function __construct()
-    {
-        if (\class_exists('\\\\EventBase', false)) {
-            $class_name = '\\\\EventBase';
-        } else {
-            $class_name = '\EventBase';
-        }
-        $this->_eventBase = new $class_name();
-    }
-   
-    /**
-     * @see EventInterface::add()
-     */
-    public function add($fd, $flag, $func, $args=array())
-    {
-        if (\class_exists('\\\\Event', false)) {
-            $class_name = '\\\\Event';
-        } else {
-            $class_name = '\Event';
-        }
-        switch ($flag) {
-            case self::EV_SIGNAL:
-
-                $fd_key = (int)$fd;
-                $event = $class_name::signal($this->_eventBase, $fd, $func);
-                if (!$event||!$event->add()) {
-                    return false;
-                }
-                $this->_eventSignal[$fd_key] = $event;
-                return true;
-
-            case self::EV_TIMER:
-            case self::EV_TIMER_ONCE:
-
-                $param = array($func, (array)$args, $flag, $fd, self::$_timerId);
-                $event = new $class_name($this->_eventBase, -1, $class_name::TIMEOUT|$class_name::PERSIST, array($this, "timerCallback"), $param);
-                if (!$event||!$event->addTimer($fd)) {
-                    return false;
-                }
-                $this->_eventTimer[self::$_timerId] = $event;
-                return self::$_timerId++;
-                
-            default :
-                $fd_key = (int)$fd;
-                $real_flag = $flag === self::EV_READ ? $class_name::READ | $class_name::PERSIST : $class_name::WRITE | $class_name::PERSIST;
-                $event = new $class_name($this->_eventBase, $fd, $real_flag, $func, $fd);
-                if (!$event||!$event->add()) {
-                    return false;
-                }
-                $this->_allEvents[$fd_key][$flag] = $event;
-                return true;
-        }
-    }
-    
-    /**
-     * @see Events\EventInterface::del()
-     */
-    public function del($fd, $flag)
-    {
-        switch ($flag) {
-
-            case self::EV_READ:
-            case self::EV_WRITE:
-
-                $fd_key = (int)$fd;
-                if (isset($this->_allEvents[$fd_key][$flag])) {
-                    $this->_allEvents[$fd_key][$flag]->del();
-                    unset($this->_allEvents[$fd_key][$flag]);
-                }
-                if (empty($this->_allEvents[$fd_key])) {
-                    unset($this->_allEvents[$fd_key]);
-                }
-                break;
-
-            case  self::EV_SIGNAL:
-                $fd_key = (int)$fd;
-                if (isset($this->_eventSignal[$fd_key])) {
-                    $this->_eventSignal[$fd_key]->del();
-                    unset($this->_eventSignal[$fd_key]);
-                }
-                break;
-
-            case self::EV_TIMER:
-            case self::EV_TIMER_ONCE:
-                if (isset($this->_eventTimer[$fd])) {
-                    $this->_eventTimer[$fd]->del();
-                    unset($this->_eventTimer[$fd]);
-                }
-                break;
-        }
-        return true;
-    }
-    
-    /**
-     * Timer callback.
-     * @param int|null $fd
-     * @param int $what
-     * @param int $timer_id
-     */
-    public function timerCallback($fd, $what, $param)
-    {
-        $timer_id = $param[4];
-        
-        if ($param[2] === self::EV_TIMER_ONCE) {
-            $this->_eventTimer[$timer_id]->del();
-            unset($this->_eventTimer[$timer_id]);
-        }
-
-        try {
-            \call_user_func_array($param[0], $param[1]);
-        } catch (\Exception $e) {
-            Worker::stopAll(250, $e);
-        } catch (\Error $e) {
-            Worker::stopAll(250, $e);
-        }
-    }
-    
-    /**
-     * @see Events\EventInterface::clearAllTimer() 
-     * @return void
-     */
-    public function clearAllTimer()
-    {
-        foreach ($this->_eventTimer as $event) {
-            $event->del();
-        }
-        $this->_eventTimer = array();
-    }
-     
-
-    /**
-     * @see EventInterface::loop()
-     */
-    public function loop()
-    {
-        $this->_eventBase->loop();
-    }
-
-    /**
-     * Destroy loop.
-     *
-     * @return void
-     */
-    public function destroy()
-    {
-        $this->_eventBase->exit();
-    }
-
-    /**
-     * Get timer count.
-     *
-     * @return integer
-     */
-    public function getTimerCount()
-    {
-        return \count($this->_eventTimer);
-    }
-}

+ 0 - 107
Events/EventInterface.php

@@ -1,107 +0,0 @@
-<?php
-/**
- * This file is part of workerman.
- *
- * Licensed under The MIT License
- * For full copyright and license information, please see the MIT-LICENSE.txt
- * Redistributions of files must retain the above copyright notice.
- *
- * @author    walkor<walkor@workerman.net>
- * @copyright walkor<walkor@workerman.net>
- * @link      http://www.workerman.net/
- * @license   http://www.opensource.org/licenses/mit-license.php MIT License
- */
-namespace Workerman\Events;
-
-interface EventInterface
-{
-    /**
-     * Read event.
-     *
-     * @var int
-     */
-    const EV_READ = 1;
-
-    /**
-     * Write event.
-     *
-     * @var int
-     */
-    const EV_WRITE = 2;
-
-    /**
-     * Except event
-     *
-     * @var int
-     */
-    const EV_EXCEPT = 3;
-
-    /**
-     * Signal event.
-     *
-     * @var int
-     */
-    const EV_SIGNAL = 4;
-
-    /**
-     * Timer event.
-     *
-     * @var int
-     */
-    const EV_TIMER = 8;
-
-    /**
-     * Timer once event.
-     *
-     * @var int
-     */
-    const EV_TIMER_ONCE = 16;
-
-    /**
-     * Add event listener to event loop.
-     *
-     * @param mixed    $fd
-     * @param int      $flag
-     * @param callable $func
-     * @param array    $args
-     * @return bool
-     */
-    public function add($fd, $flag, $func, $args = array());
-
-    /**
-     * Remove event listener from event loop.
-     *
-     * @param mixed $fd
-     * @param int   $flag
-     * @return bool
-     */
-    public function del($fd, $flag);
-
-    /**
-     * Remove all timers.
-     *
-     * @return void
-     */
-    public function clearAllTimer();
-
-    /**
-     * Main loop.
-     *
-     * @return void
-     */
-    public function loop();
-
-    /**
-     * Destroy loop.
-     *
-     * @return mixed
-     */
-    public function destroy();
-
-    /**
-     * Get Timer count.
-     *
-     * @return mixed
-     */
-    public function getTimerCount();
-}

+ 0 - 225
Events/Libevent.php

@@ -1,225 +0,0 @@
-<?php
-/**
- * This file is part of workerman.
- *
- * Licensed under The MIT License
- * For full copyright and license information, please see the MIT-LICENSE.txt
- * Redistributions of files must retain the above copyright notice.
- *
- * @author    walkor<walkor@workerman.net>
- * @copyright walkor<walkor@workerman.net>
- * @link      http://www.workerman.net/
- * @license   http://www.opensource.org/licenses/mit-license.php MIT License
- */
-namespace Workerman\Events;
-
-use Workerman\Worker;
-
-/**
- * libevent eventloop
- */
-class Libevent implements EventInterface
-{
-    /**
-     * Event base.
-     *
-     * @var resource
-     */
-    protected $_eventBase = null;
-
-    /**
-     * All listeners for read/write event.
-     *
-     * @var array
-     */
-    protected $_allEvents = array();
-
-    /**
-     * Event listeners of signal.
-     *
-     * @var array
-     */
-    protected $_eventSignal = array();
-
-    /**
-     * All timer event listeners.
-     * [func, args, event, flag, time_interval]
-     *
-     * @var array
-     */
-    protected $_eventTimer = array();
-
-    /**
-     * construct
-     */
-    public function __construct()
-    {
-        $this->_eventBase = \event_base_new();
-    }
-
-    /**
-     * {@inheritdoc}
-     */
-    public function add($fd, $flag, $func, $args = array())
-    {
-        switch ($flag) {
-            case self::EV_SIGNAL:
-                $fd_key                      = (int)$fd;
-                $real_flag                   = \EV_SIGNAL | \EV_PERSIST;
-                $this->_eventSignal[$fd_key] = \event_new();
-                if (!\event_set($this->_eventSignal[$fd_key], $fd, $real_flag, $func, null)) {
-                    return false;
-                }
-                if (!\event_base_set($this->_eventSignal[$fd_key], $this->_eventBase)) {
-                    return false;
-                }
-                if (!\event_add($this->_eventSignal[$fd_key])) {
-                    return false;
-                }
-                return true;
-            case self::EV_TIMER:
-            case self::EV_TIMER_ONCE:
-                $event    = \event_new();
-                $timer_id = (int)$event;
-                if (!\event_set($event, 0, \EV_TIMEOUT, array($this, 'timerCallback'), $timer_id)) {
-                    return false;
-                }
-
-                if (!\event_base_set($event, $this->_eventBase)) {
-                    return false;
-                }
-
-                $time_interval = $fd * 1000000;
-                if (!\event_add($event, $time_interval)) {
-                    return false;
-                }
-                $this->_eventTimer[$timer_id] = array($func, (array)$args, $event, $flag, $time_interval);
-                return $timer_id;
-
-            default :
-                $fd_key    = (int)$fd;
-                $real_flag = $flag === self::EV_READ ? \EV_READ | \EV_PERSIST : \EV_WRITE | \EV_PERSIST;
-
-                $event = \event_new();
-
-                if (!\event_set($event, $fd, $real_flag, $func, null)) {
-                    return false;
-                }
-
-                if (!\event_base_set($event, $this->_eventBase)) {
-                    return false;
-                }
-
-                if (!\event_add($event)) {
-                    return false;
-                }
-
-                $this->_allEvents[$fd_key][$flag] = $event;
-
-                return true;
-        }
-
-    }
-
-    /**
-     * {@inheritdoc}
-     */
-    public function del($fd, $flag)
-    {
-        switch ($flag) {
-            case self::EV_READ:
-            case self::EV_WRITE:
-                $fd_key = (int)$fd;
-                if (isset($this->_allEvents[$fd_key][$flag])) {
-                    \event_del($this->_allEvents[$fd_key][$flag]);
-                    unset($this->_allEvents[$fd_key][$flag]);
-                }
-                if (empty($this->_allEvents[$fd_key])) {
-                    unset($this->_allEvents[$fd_key]);
-                }
-                break;
-            case  self::EV_SIGNAL:
-                $fd_key = (int)$fd;
-                if (isset($this->_eventSignal[$fd_key])) {
-                    \event_del($this->_eventSignal[$fd_key]);
-                    unset($this->_eventSignal[$fd_key]);
-                }
-                break;
-            case self::EV_TIMER:
-            case self::EV_TIMER_ONCE:
-                // 这里 fd 为timerid 
-                if (isset($this->_eventTimer[$fd])) {
-                    \event_del($this->_eventTimer[$fd][2]);
-                    unset($this->_eventTimer[$fd]);
-                }
-                break;
-        }
-        return true;
-    }
-
-    /**
-     * Timer callback.
-     *
-     * @param mixed $_null1
-     * @param int   $_null2
-     * @param mixed $timer_id
-     */
-    protected function timerCallback($_null1, $_null2, $timer_id)
-    {
-        if ($this->_eventTimer[$timer_id][3] === self::EV_TIMER) {
-            \event_add($this->_eventTimer[$timer_id][2], $this->_eventTimer[$timer_id][4]);
-        }
-        try {
-            \call_user_func_array($this->_eventTimer[$timer_id][0], $this->_eventTimer[$timer_id][1]);
-        } catch (\Exception $e) {
-            Worker::stopAll(250, $e);
-        } catch (\Error $e) {
-            Worker::stopAll(250, $e);
-        }
-        if (isset($this->_eventTimer[$timer_id]) && $this->_eventTimer[$timer_id][3] === self::EV_TIMER_ONCE) {
-            $this->del($timer_id, self::EV_TIMER_ONCE);
-        }
-    }
-
-    /**
-     * {@inheritdoc}
-     */
-    public function clearAllTimer()
-    {
-        foreach ($this->_eventTimer as $task_data) {
-            \event_del($task_data[2]);
-        }
-        $this->_eventTimer = array();
-    }
-
-    /**
-     * {@inheritdoc}
-     */
-    public function loop()
-    {
-        \event_base_loop($this->_eventBase);
-    }
-
-    /**
-     * Destroy loop.
-     *
-     * @return void
-     */
-    public function destroy()
-    {
-        foreach ($this->_eventSignal as $event) {
-            \event_del($event);
-        }
-    }
-
-    /**
-     * Get timer count.
-     *
-     * @return integer
-     */
-    public function getTimerCount()
-    {
-        return \count($this->_eventTimer);
-    }
-}
-

+ 0 - 264
Events/React/Base.php

@@ -1,264 +0,0 @@
-<?php
-/**
- * This file is part of workerman.
- *
- * Licensed under The MIT License
- * For full copyright and license information, please see the MIT-LICENSE.txt
- * Redistributions of files must retain the above copyright notice.
- *
- * @author    walkor<walkor@workerman.net>
- * @copyright walkor<walkor@workerman.net>
- * @link      http://www.workerman.net/
- * @license   http://www.opensource.org/licenses/mit-license.php MIT License
- */
-namespace Workerman\Events\React;
-
-use Workerman\Events\EventInterface;
-use React\EventLoop\TimerInterface;
-use React\EventLoop\LoopInterface;
-
-/**
- * Class StreamSelectLoop
- * @package Workerman\Events\React
- */
-class Base implements LoopInterface
-{
-    /**
-     * @var array
-     */
-    protected $_timerIdMap = array();
-
-    /**
-     * @var int
-     */
-    protected $_timerIdIndex = 0;
-
-    /**
-     * @var array
-     */
-    protected $_signalHandlerMap = array();
-
-    /**
-     * @var LoopInterface
-     */
-    protected $_eventLoop = null;
-
-    /**
-     * Base constructor.
-     */
-    public function __construct()
-    {
-        $this->_eventLoop = new \React\EventLoop\StreamSelectLoop();
-    }
-
-    /**
-     * Add event listener to event loop.
-     *
-     * @param int $fd
-     * @param int $flag
-     * @param callable $func
-     * @param array $args
-     * @return bool
-     */
-    public function add($fd, $flag, $func, array $args = array())
-    {
-        $args = (array)$args;
-        switch ($flag) {
-            case EventInterface::EV_READ:
-                return $this->addReadStream($fd, $func);
-            case EventInterface::EV_WRITE:
-                return $this->addWriteStream($fd, $func);
-            case EventInterface::EV_SIGNAL:
-                if (isset($this->_signalHandlerMap[$fd])) {
-                    $this->removeSignal($fd, $this->_signalHandlerMap[$fd]);
-                }
-                $this->_signalHandlerMap[$fd] = $func;
-                return $this->addSignal($fd, $func);
-            case EventInterface::EV_TIMER:
-                $timer_obj = $this->addPeriodicTimer($fd, function() use ($func, $args) {
-                    \call_user_func_array($func, $args);
-                });
-                $this->_timerIdMap[++$this->_timerIdIndex] = $timer_obj;
-                return $this->_timerIdIndex;
-            case EventInterface::EV_TIMER_ONCE:
-                $index = ++$this->_timerIdIndex;
-                $timer_obj = $this->addTimer($fd, function() use ($func, $args, $index) {
-                    $this->del($index,EventInterface::EV_TIMER_ONCE);
-                    \call_user_func_array($func, $args);
-                });
-                $this->_timerIdMap[$index] = $timer_obj;
-                return $this->_timerIdIndex;
-        }
-        return false;
-    }
-
-    /**
-     * Remove event listener from event loop.
-     *
-     * @param mixed $fd
-     * @param int   $flag
-     * @return bool
-     */
-    public function del($fd, $flag)
-    {
-        switch ($flag) {
-            case EventInterface::EV_READ:
-                return $this->removeReadStream($fd);
-            case EventInterface::EV_WRITE:
-                return $this->removeWriteStream($fd);
-            case EventInterface::EV_SIGNAL:
-                if (!isset($this->_eventLoop[$fd])) {
-                    return false;
-                }
-                $func = $this->_eventLoop[$fd];
-                unset($this->_eventLoop[$fd]);
-                return $this->removeSignal($fd, $func);
-
-            case EventInterface::EV_TIMER:
-            case EventInterface::EV_TIMER_ONCE:
-                if (isset($this->_timerIdMap[$fd])){
-                    $timer_obj = $this->_timerIdMap[$fd];
-                    unset($this->_timerIdMap[$fd]);
-                    $this->cancelTimer($timer_obj);
-                    return true;
-                }
-        }
-        return false;
-    }
-
-
-    /**
-     * Main loop.
-     *
-     * @return void
-     */
-    public function loop()
-    {
-        $this->run();
-    }
-
-
-    /**
-     * Destroy loop.
-     *
-     * @return void
-     */
-    public function destroy()
-    {
-
-    }
-
-    /**
-     * Get timer count.
-     *
-     * @return integer
-     */
-    public function getTimerCount()
-    {
-        return \count($this->_timerIdMap);
-    }
-
-    /**
-     * @param resource $stream
-     * @param callable $listener
-     */
-    public function addReadStream($stream, $listener)
-    {
-        return $this->_eventLoop->addReadStream($stream, $listener);
-    }
-
-    /**
-     * @param resource $stream
-     * @param callable $listener
-     */
-    public function addWriteStream($stream, $listener)
-    {
-        return $this->_eventLoop->addWriteStream($stream, $listener);
-    }
-
-    /**
-     * @param resource $stream
-     */
-    public function removeReadStream($stream)
-    {
-        return $this->_eventLoop->removeReadStream($stream);
-    }
-
-    /**
-     * @param resource $stream
-     */
-    public function removeWriteStream($stream)
-    {
-        return $this->_eventLoop->removeWriteStream($stream);
-    }
-
-    /**
-     * @param float|int $interval
-     * @param callable $callback
-     * @return \React\EventLoop\Timer\Timer|TimerInterface
-     */
-    public function addTimer($interval, $callback)
-    {
-        return $this->_eventLoop->addTimer($interval, $callback);
-    }
-
-    /**
-     * @param float|int $interval
-     * @param callable $callback
-     * @return \React\EventLoop\Timer\Timer|TimerInterface
-     */
-    public function addPeriodicTimer($interval, $callback)
-    {
-        return $this->_eventLoop->addPeriodicTimer($interval, $callback);
-    }
-
-    /**
-     * @param TimerInterface $timer
-     */
-    public function cancelTimer(TimerInterface $timer)
-    {
-        return $this->_eventLoop->cancelTimer($timer);
-    }
-
-    /**
-     * @param callable $listener
-     */
-    public function futureTick($listener)
-    {
-        return $this->_eventLoop->futureTick($listener);
-    }
-
-    /**
-     * @param int $signal
-     * @param callable $listener
-     */
-    public function addSignal($signal, $listener)
-    {
-        return $this->_eventLoop->addSignal($signal, $listener);
-    }
-
-    /**
-     * @param int $signal
-     * @param callable $listener
-     */
-    public function removeSignal($signal, $listener)
-    {
-        return $this->_eventLoop->removeSignal($signal, $listener);
-    }
-
-    /**
-     * Run.
-     */
-    public function run()
-    {
-        return $this->_eventLoop->run();
-    }
-
-    /**
-     * Stop.
-     */
-    public function stop()
-    {
-        return $this->_eventLoop->stop();
-    }
-}

+ 0 - 27
Events/React/ExtEventLoop.php

@@ -1,27 +0,0 @@
-<?php
-/**
- * This file is part of workerman.
- *
- * Licensed under The MIT License
- * For full copyright and license information, please see the MIT-LICENSE.txt
- * Redistributions of files must retain the above copyright notice.
- *
- * @author    walkor<walkor@workerman.net>
- * @copyright walkor<walkor@workerman.net>
- * @link      http://www.workerman.net/
- * @license   http://www.opensource.org/licenses/mit-license.php MIT License
- */
-namespace Workerman\Events\React;
-
-/**
- * Class ExtEventLoop
- * @package Workerman\Events\React
- */
-class ExtEventLoop extends Base
-{
-
-    public function __construct()
-    {
-        $this->_eventLoop = new \React\EventLoop\ExtEventLoop();
-    }
-}

+ 0 - 27
Events/React/ExtLibEventLoop.php

@@ -1,27 +0,0 @@
-<?php
-/**
- * This file is part of workerman.
- *
- * Licensed under The MIT License
- * For full copyright and license information, please see the MIT-LICENSE.txt
- * Redistributions of files must retain the above copyright notice.
- *
- * @author    walkor<walkor@workerman.net>
- * @copyright walkor<walkor@workerman.net>
- * @link      http://www.workerman.net/
- * @license   http://www.opensource.org/licenses/mit-license.php MIT License
- */
-namespace Workerman\Events\React;
-use Workerman\Events\EventInterface;
-
-/**
- * Class ExtLibEventLoop
- * @package Workerman\Events\React
- */
-class ExtLibEventLoop extends Base
-{
-    public function __construct()
-    {
-        $this->_eventLoop = new \React\EventLoop\ExtLibeventLoop();
-    }
-}

+ 0 - 26
Events/React/StreamSelectLoop.php

@@ -1,26 +0,0 @@
-<?php
-/**
- * This file is part of workerman.
- *
- * Licensed under The MIT License
- * For full copyright and license information, please see the MIT-LICENSE.txt
- * Redistributions of files must retain the above copyright notice.
- *
- * @author    walkor<walkor@workerman.net>
- * @copyright walkor<walkor@workerman.net>
- * @link      http://www.workerman.net/
- * @license   http://www.opensource.org/licenses/mit-license.php MIT License
- */
-namespace Workerman\Events\React;
-
-/**
- * Class StreamSelectLoop
- * @package Workerman\Events\React
- */
-class StreamSelectLoop extends Base
-{
-    public function __construct()
-    {
-        $this->_eventLoop = new \React\EventLoop\StreamSelectLoop();
-    }
-}

+ 0 - 341
Events/Select.php

@@ -1,341 +0,0 @@
-<?php
-/**
- * This file is part of workerman.
- *
- * Licensed under The MIT License
- * For full copyright and license information, please see the MIT-LICENSE.txt
- * Redistributions of files must retain the above copyright notice.
- *
- * @author    walkor<walkor@workerman.net>
- * @copyright walkor<walkor@workerman.net>
- * @link      http://www.workerman.net/
- * @license   http://www.opensource.org/licenses/mit-license.php MIT License
- */
-namespace Workerman\Events;
-
-/**
- * select eventloop
- */
-class Select implements EventInterface
-{
-    /**
-     * All listeners for read/write event.
-     *
-     * @var array
-     */
-    public $_allEvents = array();
-
-    /**
-     * Event listeners of signal.
-     *
-     * @var array
-     */
-    public $_signalEvents = array();
-
-    /**
-     * Fds waiting for read event.
-     *
-     * @var array
-     */
-    protected $_readFds = array();
-
-    /**
-     * Fds waiting for write event.
-     *
-     * @var array
-     */
-    protected $_writeFds = array();
-
-    /**
-     * Fds waiting for except event.
-     *
-     * @var array
-     */
-    protected $_exceptFds = array();
-
-    /**
-     * Timer scheduler.
-     * {['data':timer_id, 'priority':run_timestamp], ..}
-     *
-     * @var \SplPriorityQueue
-     */
-    protected $_scheduler = null;
-
-    /**
-     * All timer event listeners.
-     * [[func, args, flag, timer_interval], ..]
-     *
-     * @var array
-     */
-    protected $_eventTimer = array();
-
-    /**
-     * Timer id.
-     *
-     * @var int
-     */
-    protected $_timerId = 1;
-
-    /**
-     * Select timeout.
-     *
-     * @var int
-     */
-    protected $_selectTimeout = 100000000;
-
-    /**
-     * Paired socket channels
-     *
-     * @var array
-     */
-    protected $channel = array();
-
-    /**
-     * Construct.
-     */
-    public function __construct()
-    {
-        // Init SplPriorityQueue.
-        $this->_scheduler = new \SplPriorityQueue();
-        $this->_scheduler->setExtractFlags(\SplPriorityQueue::EXTR_BOTH);
-    }
-
-    /**
-     * {@inheritdoc}
-     */
-    public function add($fd, $flag, $func, $args = array())
-    {
-        switch ($flag) {
-            case self::EV_READ:
-            case self::EV_WRITE:
-                $count = $flag === self::EV_READ ? \count($this->_readFds) : \count($this->_writeFds);
-                if ($count >= 1024) {
-                    echo "Warning: system call select exceeded the maximum number of connections 1024, please install event/libevent extension for more connections.\n";
-                } else if (\DIRECTORY_SEPARATOR !== '/' && $count >= 256) {
-                    echo "Warning: system call select exceeded the maximum number of connections 256.\n";
-                }
-                $fd_key                           = (int)$fd;
-                $this->_allEvents[$fd_key][$flag] = array($func, $fd);
-                if ($flag === self::EV_READ) {
-                    $this->_readFds[$fd_key] = $fd;
-                } else {
-                    $this->_writeFds[$fd_key] = $fd;
-                }
-                break;
-            case self::EV_EXCEPT:
-                $fd_key = (int)$fd;
-                $this->_allEvents[$fd_key][$flag] = array($func, $fd);
-                $this->_exceptFds[$fd_key] = $fd;
-                break;
-            case self::EV_SIGNAL:
-                // Windows not support signal.
-                if(\DIRECTORY_SEPARATOR !== '/') {
-                    return false;
-                }
-                $fd_key                              = (int)$fd;
-                $this->_signalEvents[$fd_key][$flag] = array($func, $fd);
-                \pcntl_signal($fd, array($this, 'signalHandler'));
-                break;
-            case self::EV_TIMER:
-            case self::EV_TIMER_ONCE:
-                $timer_id = $this->_timerId++;
-                $run_time = \microtime(true) + $fd;
-                $this->_scheduler->insert($timer_id, -$run_time);
-                $this->_eventTimer[$timer_id] = array($func, (array)$args, $flag, $fd);
-                $select_timeout = ($run_time - \microtime(true)) * 1000000;
-                $select_timeout = $select_timeout <= 0 ? 1 : $select_timeout;
-                if( $this->_selectTimeout > $select_timeout ){ 
-                    $this->_selectTimeout = (int) $select_timeout;   
-                }  
-                return $timer_id;
-        }
-
-        return true;
-    }
-
-    /**
-     * Signal handler.
-     *
-     * @param int $signal
-     */
-    public function signalHandler($signal)
-    {
-        \call_user_func_array($this->_signalEvents[$signal][self::EV_SIGNAL][0], array($signal));
-    }
-
-    /**
-     * {@inheritdoc}
-     */
-    public function del($fd, $flag)
-    {
-        $fd_key = (int)$fd;
-        switch ($flag) {
-            case self::EV_READ:
-                unset($this->_allEvents[$fd_key][$flag], $this->_readFds[$fd_key]);
-                if (empty($this->_allEvents[$fd_key])) {
-                    unset($this->_allEvents[$fd_key]);
-                }
-                return true;
-            case self::EV_WRITE:
-                unset($this->_allEvents[$fd_key][$flag], $this->_writeFds[$fd_key]);
-                if (empty($this->_allEvents[$fd_key])) {
-                    unset($this->_allEvents[$fd_key]);
-                }
-                return true;
-            case self::EV_EXCEPT:
-                unset($this->_allEvents[$fd_key][$flag], $this->_exceptFds[$fd_key]);
-                if(empty($this->_allEvents[$fd_key]))
-                {
-                    unset($this->_allEvents[$fd_key]);
-                }
-                return true;
-            case self::EV_SIGNAL:
-                if(\DIRECTORY_SEPARATOR !== '/') {
-                    return false;
-                }
-                unset($this->_signalEvents[$fd_key]);
-                \pcntl_signal($fd, SIG_IGN);
-                break;
-            case self::EV_TIMER:
-            case self::EV_TIMER_ONCE;
-                unset($this->_eventTimer[$fd_key]);
-                return true;
-        }
-        return false;
-    }
-
-    /**
-     * Tick for timer.
-     *
-     * @return void
-     */
-    protected function tick()
-    {
-        while (!$this->_scheduler->isEmpty()) {
-            $scheduler_data       = $this->_scheduler->top();
-            $timer_id             = $scheduler_data['data'];
-            $next_run_time        = -$scheduler_data['priority'];
-            $time_now             = \microtime(true);
-            $this->_selectTimeout = (int) (($next_run_time - $time_now) * 1000000);
-            if ($this->_selectTimeout <= 0) {
-                $this->_scheduler->extract();
-
-                if (!isset($this->_eventTimer[$timer_id])) {
-                    continue;
-                }
-
-                // [func, args, flag, timer_interval]
-                $task_data = $this->_eventTimer[$timer_id];
-                if ($task_data[2] === self::EV_TIMER) {
-                    $next_run_time = $time_now + $task_data[3];
-                    $this->_scheduler->insert($timer_id, -$next_run_time);
-                }
-                \call_user_func_array($task_data[0], $task_data[1]);
-                if (isset($this->_eventTimer[$timer_id]) && $task_data[2] === self::EV_TIMER_ONCE) {
-                    $this->del($timer_id, self::EV_TIMER_ONCE);
-                }
-                continue;
-            }
-            return;
-        }
-        $this->_selectTimeout = 100000000;
-    }
-
-    /**
-     * {@inheritdoc}
-     */
-    public function clearAllTimer()
-    {
-        $this->_scheduler = new \SplPriorityQueue();
-        $this->_scheduler->setExtractFlags(\SplPriorityQueue::EXTR_BOTH);
-        $this->_eventTimer = array();
-    }
-
-    /**
-     * {@inheritdoc}
-     */
-    public function loop()
-    {
-        while (1) {
-            if(\DIRECTORY_SEPARATOR === '/') {
-                // Calls signal handlers for pending signals
-                \pcntl_signal_dispatch();
-            }
-
-            $read   = $this->_readFds;
-            $write  = $this->_writeFds;
-            $except = $this->_exceptFds;
-            $ret    = false;
-
-            if ($read || $write || $except) {
-                // Waiting read/write/signal/timeout events.
-                try {
-                    $ret = @stream_select($read, $write, $except, 0, $this->_selectTimeout);
-                } catch (\Exception $e) {} catch (\Error $e) {}
-
-            } else {
-                $this->_selectTimeout >= 1 && usleep($this->_selectTimeout);
-                $ret = false;
-            }
-
-
-            if (!$this->_scheduler->isEmpty()) {
-                $this->tick();
-            }
-
-            if (!$ret) {
-                continue;
-            }
-
-            if ($read) {
-                foreach ($read as $fd) {
-                    $fd_key = (int)$fd;
-                    if (isset($this->_allEvents[$fd_key][self::EV_READ])) {
-                        \call_user_func_array($this->_allEvents[$fd_key][self::EV_READ][0],
-                            array($this->_allEvents[$fd_key][self::EV_READ][1]));
-                    }
-                }
-            }
-
-            if ($write) {
-                foreach ($write as $fd) {
-                    $fd_key = (int)$fd;
-                    if (isset($this->_allEvents[$fd_key][self::EV_WRITE])) {
-                        \call_user_func_array($this->_allEvents[$fd_key][self::EV_WRITE][0],
-                            array($this->_allEvents[$fd_key][self::EV_WRITE][1]));
-                    }
-                }
-            }
-
-            if($except) {
-                foreach($except as $fd) {
-                    $fd_key = (int) $fd;
-                    if(isset($this->_allEvents[$fd_key][self::EV_EXCEPT])) {
-                        \call_user_func_array($this->_allEvents[$fd_key][self::EV_EXCEPT][0],
-                            array($this->_allEvents[$fd_key][self::EV_EXCEPT][1]));
-                    }
-                }
-            }
-        }
-    }
-
-    /**
-     * Destroy loop.
-     *
-     * @return void
-     */
-    public function destroy()
-    {
-
-    }
-
-    /**
-     * Get timer count.
-     *
-     * @return integer
-     */
-    public function getTimerCount()
-    {
-        return \count($this->_eventTimer);
-    }
-}

+ 0 - 230
Events/Swoole.php

@@ -1,230 +0,0 @@
-<?php
-/**
- * This file is part of workerman.
- *
- * Licensed under The MIT License
- * For full copyright and license information, please see the MIT-LICENSE.txt
- * Redistributions of files must retain the above copyright notice.
- *
- * @author    Ares<aresrr#qq.com>
- * @link      http://www.workerman.net/
- * @link      https://github.com/ares333/Workerman
- * @license   http://www.opensource.org/licenses/mit-license.php MIT License
- */
-namespace Workerman\Events;
-
-use Workerman\Worker;
-use Swoole\Event;
-use Swoole\Timer;
-
-class Swoole implements EventInterface
-{
-
-    protected $_timer = array();
-
-    protected $_timerOnceMap = array();
-
-    protected $mapId = 0;
-
-    protected $_fd = array();
-
-    // milisecond
-    public static $signalDispatchInterval = 500;
-
-    protected $_hasSignal = false;
-
-    /**
-     *
-     * {@inheritdoc}
-     *
-     * @see \Workerman\Events\EventInterface::add()
-     */
-    public function add($fd, $flag, $func, $args = array())
-    {
-        switch ($flag) {
-            case self::EV_SIGNAL:
-                $res = \pcntl_signal($fd, $func, false);
-                if (! $this->_hasSignal && $res) {
-                    Timer::tick(static::$signalDispatchInterval,
-                        function () {
-                            \pcntl_signal_dispatch();
-                        });
-                    $this->_hasSignal = true;
-                }
-                return $res;
-            case self::EV_TIMER:
-            case self::EV_TIMER_ONCE:
-                $method = self::EV_TIMER === $flag ? 'tick' : 'after';
-                if ($this->mapId > \PHP_INT_MAX) {
-                    $this->mapId = 0;
-                }
-                $mapId = $this->mapId++;
-                $t = (int)($fd * 1000);
-                if ($t < 1) {
-                   $t = 1;   
-                }
-                $timer_id = Timer::$method($t,
-                    function ($timer_id = null) use ($func, $args, $mapId) {
-                        try {
-                            \call_user_func_array($func, (array)$args);
-                        } catch (\Exception $e) {
-                            Worker::stopAll(250, $e);
-                        } catch (\Error $e) {
-                            Worker::stopAll(250, $e);
-                        }
-                        // EV_TIMER_ONCE
-                        if (! isset($timer_id)) {
-                            // may be deleted in $func
-                            if (\array_key_exists($mapId, $this->_timerOnceMap)) {
-                                $timer_id = $this->_timerOnceMap[$mapId];
-                                unset($this->_timer[$timer_id],
-                                    $this->_timerOnceMap[$mapId]);
-                            }
-                        }
-                    });
-                if ($flag === self::EV_TIMER_ONCE) {
-                    $this->_timerOnceMap[$mapId] = $timer_id;
-                    $this->_timer[$timer_id] = $mapId;
-                } else {
-                    $this->_timer[$timer_id] = null;
-                }
-                return $timer_id;
-            case self::EV_READ:
-            case self::EV_WRITE:
-                $fd_key = (int) $fd;
-                if (! isset($this->_fd[$fd_key])) {
-                    if ($flag === self::EV_READ) {
-                        $res = Event::add($fd, $func, null, SWOOLE_EVENT_READ);
-                        $fd_type = SWOOLE_EVENT_READ;
-                    } else {
-                        $res = Event::add($fd, null, $func, SWOOLE_EVENT_WRITE);
-                        $fd_type = SWOOLE_EVENT_WRITE;
-                    }
-                    if ($res) {
-                        $this->_fd[$fd_key] = $fd_type;
-                    }
-                } else {
-                    $fd_val = $this->_fd[$fd_key];
-                    $res = true;
-                    if ($flag === self::EV_READ) {
-                        if (($fd_val & SWOOLE_EVENT_READ) !== SWOOLE_EVENT_READ) {
-                            $res = Event::set($fd, $func, null,
-                                SWOOLE_EVENT_READ | SWOOLE_EVENT_WRITE);
-                            $this->_fd[$fd_key] |= SWOOLE_EVENT_READ;
-                        }
-                    } else {
-                        if (($fd_val & SWOOLE_EVENT_WRITE) !== SWOOLE_EVENT_WRITE) {
-                            $res = Event::set($fd, null, $func,
-                                SWOOLE_EVENT_READ | SWOOLE_EVENT_WRITE);
-                            $this->_fd[$fd_key] |= SWOOLE_EVENT_WRITE;
-                        }
-                    }
-                }
-                return $res;
-        }
-    }
-
-    /**
-     *
-     * {@inheritdoc}
-     *
-     * @see \Workerman\Events\EventInterface::del()
-     */
-    public function del($fd, $flag)
-    {
-        switch ($flag) {
-            case self::EV_SIGNAL:
-                return \pcntl_signal($fd, SIG_IGN, false);
-            case self::EV_TIMER:
-            case self::EV_TIMER_ONCE:
-                // already remove in EV_TIMER_ONCE callback.
-                if (! \array_key_exists($fd, $this->_timer)) {
-                    return true;
-                }
-                $res = Timer::clear($fd);
-                if ($res) {
-                    $mapId = $this->_timer[$fd];
-                    if (isset($mapId)) {
-                        unset($this->_timerOnceMap[$mapId]);
-                    }
-                    unset($this->_timer[$fd]);
-                }
-                return $res;
-            case self::EV_READ:
-            case self::EV_WRITE:
-                $fd_key = (int) $fd;
-                if (isset($this->_fd[$fd_key])) {
-                    $fd_val = $this->_fd[$fd_key];
-                    if ($flag === self::EV_READ) {
-                        $flag_remove = ~ SWOOLE_EVENT_READ;
-                    } else {
-                        $flag_remove = ~ SWOOLE_EVENT_WRITE;
-                    }
-                    $fd_val &= $flag_remove;
-                    if (0 === $fd_val) {
-                        $res = Event::del($fd);
-                        if ($res) {
-                            unset($this->_fd[$fd_key]);
-                        }
-                    } else {
-                        $res = Event::set($fd, null, null, $fd_val);
-                        if ($res) {
-                            $this->_fd[$fd_key] = $fd_val;
-                        }
-                    }
-                } else {
-                    $res = true;
-                }
-                return $res;
-        }
-    }
-
-    /**
-     *
-     * {@inheritdoc}
-     *
-     * @see \Workerman\Events\EventInterface::clearAllTimer()
-     */
-    public function clearAllTimer()
-    {
-        foreach (array_keys($this->_timer) as $v) {
-            Timer::clear($v);
-        }
-        $this->_timer = array();
-        $this->_timerOnceMap = array();
-    }
-
-    /**
-     *
-     * {@inheritdoc}
-     *
-     * @see \Workerman\Events\EventInterface::loop()
-     */
-    public function loop()
-    {
-        Event::wait();
-    }
-
-    /**
-     *
-     * {@inheritdoc}
-     *
-     * @see \Workerman\Events\EventInterface::destroy()
-     */
-    public function destroy()
-    {
-        Event::exit();
-        posix_kill(posix_getpid(), SIGINT);
-    }
-
-    /**
-     *
-     * {@inheritdoc}
-     *
-     * @see \Workerman\Events\EventInterface::getTimerCount()
-     */
-    public function getTimerCount()
-    {
-        return \count($this->_timer);
-    }
-}

+ 0 - 44
Lib/Constants.php

@@ -1,44 +0,0 @@
-<?php
-/**
- * This file is part of workerman.
- *
- * Licensed under The MIT License
- * For full copyright and license information, please see the MIT-LICENSE.txt
- * Redistributions of files must retain the above copyright notice.
- *
- * @author    walkor<walkor@workerman.net>
- * @copyright walkor<walkor@workerman.net>
- * @license   http://www.opensource.org/licenses/mit-license.php MIT License
- *
- * @link      http://www.workerman.net/
- */
-
-// Pcre.jit is not stable, temporarily disabled.
-ini_set('pcre.jit', 0);
-
-// For onError callback.
-const WORKERMAN_CONNECT_FAIL = 1;
-// For onError callback.
-const WORKERMAN_SEND_FAIL = 2;
-
-// Define OS Type
-const OS_TYPE_LINUX   = 'linux';
-const OS_TYPE_WINDOWS = 'windows';
-
-// Compatible with php7
-if (!class_exists('Error')) {
-    class Error extends Exception
-    {
-    }
-}
-
-if (!interface_exists('SessionHandlerInterface')) {
-    interface SessionHandlerInterface {
-        public function close();
-        public function destroy($session_id);
-        public function gc($maxlifetime);
-        public function open($save_path ,$session_name);
-        public function read($session_id);
-        public function write($session_id , $session_data);
-    }
-}

+ 0 - 22
Lib/Timer.php

@@ -1,22 +0,0 @@
-<?php
-/**
- * This file is part of workerman.
- *
- * Licensed under The MIT License
- * For full copyright and license information, please see the MIT-LICENSE.txt
- * Redistributions of files must retain the above copyright notice.
- *
- * @author    walkor<walkor@workerman.net>
- * @copyright walkor<walkor@workerman.net>
- * @link      http://www.workerman.net/
- * @license   http://www.opensource.org/licenses/mit-license.php MIT License
- */
-namespace Workerman\Lib;
-
-/**
- * Do not use Workerman\Lib\Timer.
- * Please use Workerman\Timer.
- * This class is only used for compatibility with workerman 3.*
- * @package Workerman\Lib
- */
-class Timer extends \Workerman\Timer {}

+ 9 - 47
README.md

@@ -58,8 +58,6 @@ Worker::runAll();
 
 ### An http server
 ```php
-<?php
-
 use Workerman\Worker;
 
 require_once __DIR__ . '/vendor/autoload.php';
@@ -91,8 +89,6 @@ Worker::runAll();
 
 ### A tcp server
 ```php
-<?php
-
 use Workerman\Worker;
 
 require_once __DIR__ . '/vendor/autoload.php';
@@ -122,29 +118,6 @@ $tcp_worker->onClose = function ($connection) {
 Worker::runAll();
 ```
 
-### A udp server
-
-```php
-<?php
-
-use Workerman\Worker;
-
-require_once __DIR__ . '/vendor/autoload.php';
-
-$worker = new Worker('udp://0.0.0.0:1234');
-
-// 4 processes
-$tcp_worker->count = 4;
-
-// Emitted when data received
-$worker->onMessage = function($connection, $data)
-{
-    $connection->send($data);
-};
-
-Worker::runAll();
-```
-
 ### Enable SSL
 ```php
 <?php
@@ -154,13 +127,13 @@ use Workerman\Worker;
 require_once __DIR__ . '/vendor/autoload.php';
 
 // SSL context.
-$context = array(
-    'ssl' => array(
+$context = [
+    'ssl' => [
         'local_cert'  => '/your/path/of/server.pem',
         'local_pk'    => '/your/path/of/server.key',
         'verify_peer' => false,
-    )
-);
+    ]
+];
 
 // Create a Websocket server with ssl context.
 $ws_worker = new Worker('websocket://0.0.0.0:2346', $context);
@@ -180,7 +153,6 @@ Worker::runAll();
 ### Custom protocol
 Protocols/MyTextProtocol.php
 ```php
-<?php
 
 namespace Protocols;
 
@@ -217,8 +189,6 @@ class MyTextProtocol
 ```
 
 ```php
-<?php
-
 use Workerman\Worker;
 
 require_once __DIR__ . '/vendor/autoload.php';
@@ -245,7 +215,6 @@ Worker::runAll();
 
 ### Timer
 ```php
-<?php
 
 use Workerman\Worker;
 use Workerman\Timer;
@@ -267,7 +236,6 @@ Worker::runAll();
 
 ### AsyncTcpConnection (tcp/ws/text/frame etc...)
 ```php
-<?php
 
 use Workerman\Worker;
 use Workerman\Connection\AsyncTcpConnection;
@@ -313,22 +281,13 @@ Worker::runAll();
 
 中文主页:[http://www.workerman.net](https://www.workerman.net)
 
-中文文档: [https://www.workerman.net/doc/workerman](https://www.workerman.net/doc/workerman)
+中文文档: [http://doc.workerman.net](https://www.workerman.net/doc/worekrman)
 
 Documentation:[https://github.com/walkor/workerman-manual](https://github.com/walkor/workerman-manual/blob/master/english/SUMMARY.md)
 
 # Benchmarks
-https://www.techempower.com/benchmarks/#section=data-r20&hw=ph&test=db&l=yyku7z-e7&a=2
-![image](https://user-images.githubusercontent.com/6073368/146704320-1559fe97-aa67-4ee3-95d6-61e341b3c93b.png)
-
-## Sponsors
-[opencollective.com/walkor](https://opencollective.com/walkor)
+https://www.techempower.com/benchmarks/#section=data-r19&hw=ph&test=plaintext&l=zik073-1r
 
-[patreon.com/walkor](https://patreon.com/walkor)
-
-## Donate
-
-<a href="https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=UQGGS9UB35WWG"><img src="http://donate.workerman.net/img/donate.png"></a>
 
 ## Other links with workerman
 
@@ -337,6 +296,9 @@ https://www.techempower.com/benchmarks/#section=data-r20&hw=ph&test=db&l=yyku7z-
 [php-socks5](https://github.com/walkor/php-socks5)  
 [php-http-proxy](https://github.com/walkor/php-http-proxy)  
 
+## Donate
+<a href="https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=UQGGS9UB35WWG"><img src="http://donate.workerman.net/img/donate.png"></a>
+
 ## LICENSE
 
 Workerman is released under the [MIT license](https://github.com/walkor/workerman/blob/master/MIT-LICENSE.txt).

+ 2 - 2
composer.json

@@ -24,14 +24,14 @@
         "source": "https://github.com/walkor/workerman"
     },
     "require": {
-        "php": ">=5.3"
+        "php": ">=7.0"
     },
     "suggest": {
         "ext-event": "For better performance. "
     },
     "autoload": {
         "psr-4": {
-            "Workerman\\": "./"
+            "Workerman\\": "src"
         }
     },
     "minimum-stability": "dev"

+ 46 - 51
Connection/AsyncTcpConnection.php → src/Connection/AsyncTcpConnection.php

@@ -11,10 +11,11 @@
  * @link      http://www.workerman.net/
  * @license   http://www.opensource.org/licenses/mit-license.php MIT License
  */
+
 namespace Workerman\Connection;
 
 use Workerman\Events\EventInterface;
-use Workerman\Lib\Timer;
+use Workerman\Timer;
 use Workerman\Worker;
 use \Exception;
 
@@ -92,15 +93,15 @@ class AsyncTcpConnection extends TcpConnection
      *
      * @var array
      */
-    protected static $_builtinTransports = array(
-        'tcp'   => 'tcp',
-        'udp'   => 'udp',
-        'unix'  => 'unix',
-        'ssl'   => 'ssl',
+    protected static $_builtinTransports = [
+        'tcp' => 'tcp',
+        'udp' => 'udp',
+        'unix' => 'unix',
+        'ssl' => 'ssl',
         'sslv2' => 'sslv2',
         'sslv3' => 'sslv3',
-        'tls'   => 'tls'
-    );
+        'tls' => 'tls'
+    ];
 
     /**
      * Construct.
@@ -109,12 +110,12 @@ class AsyncTcpConnection extends TcpConnection
      * @param array $context_option
      * @throws Exception
      */
-    public function __construct($remote_address, array $context_option = array())
+    public function __construct($remote_address, array $context_option = [])
     {
         $address_info = \parse_url($remote_address);
         if (!$address_info) {
             list($scheme, $this->_remoteAddress) = \explode(':', $remote_address, 2);
-            if('unix' === strtolower($scheme)) { 
+            if ('unix' === strtolower($scheme)) {
                 $this->_remoteAddress = substr($remote_address, strpos($remote_address, '/') + 2);
             }
             if (!$this->_remoteAddress) {
@@ -132,22 +133,22 @@ class AsyncTcpConnection extends TcpConnection
             } else {
                 $address_info['query'] = '?' . $address_info['query'];
             }
-            $this->_remoteHost    = $address_info['host'];
-            $this->_remotePort    = $address_info['port'];
-            $this->_remoteURI     = "{$address_info['path']}{$address_info['query']}";
-            $scheme               = isset($address_info['scheme']) ? $address_info['scheme'] : 'tcp';
-            $this->_remoteAddress = 'unix' === strtolower($scheme) 
-                                    ? substr($remote_address, strpos($remote_address, '/') + 2)
-                                    : $this->_remoteHost . ':' . $this->_remotePort;
+            $this->_remoteHost = $address_info['host'];
+            $this->_remotePort = $address_info['port'];
+            $this->_remoteURI = "{$address_info['path']}{$address_info['query']}";
+            $scheme = isset($address_info['scheme']) ? $address_info['scheme'] : 'tcp';
+            $this->_remoteAddress = 'unix' === strtolower($scheme)
+                ? substr($remote_address, strpos($remote_address, '/') + 2)
+                : $this->_remoteHost . ':' . $this->_remotePort;
         }
 
         $this->id = $this->_id = self::$_idRecorder++;
-        if(\PHP_INT_MAX === self::$_idRecorder){
+        if (\PHP_INT_MAX === self::$_idRecorder) {
             self::$_idRecorder = 0;
         }
         // Check application layer protocol class.
         if (!isset(self::$_builtinTransports[$scheme])) {
-            $scheme         = \ucfirst($scheme);
+            $scheme = \ucfirst($scheme);
             $this->protocol = '\\Protocols\\' . $scheme;
             if (!\class_exists($this->protocol)) {
                 $this->protocol = "\\Workerman\\Protocols\\$scheme";
@@ -161,9 +162,9 @@ class AsyncTcpConnection extends TcpConnection
 
         // For statistics.
         ++self::$statistics['connection_count'];
-        $this->maxSendBufferSize         = self::$defaultMaxSendBufferSize;
-        $this->maxPackageSize            = self::$defaultMaxPackageSize;
-        $this->_contextOption            = $context_option;
+        $this->maxSendBufferSize = self::$defaultMaxSendBufferSize;
+        $this->maxPackageSize = self::$defaultMaxPackageSize;
+        $this->_contextOption = $context_option;
         static::$connections[$this->_id] = $this;
     }
 
@@ -178,12 +179,12 @@ class AsyncTcpConnection extends TcpConnection
             $this->_status !== self::STATUS_CLOSED) {
             return;
         }
-        $this->_status           = self::STATUS_CONNECTING;
+        $this->_status = self::STATUS_CONNECTING;
         $this->_connectStartTime = \microtime(true);
         if ($this->transport !== 'unix') {
             if (!$this->_remotePort) {
                 $this->_remotePort = $this->transport === 'ssl' ? 443 : 80;
-                $this->_remoteAddress = $this->_remoteHost.':'.$this->_remotePort;
+                $this->_remoteAddress = $this->_remoteHost . ':' . $this->_remotePort;
             }
             // Open socket connection asynchronously.
             if ($this->_contextOption) {
@@ -200,7 +201,7 @@ class AsyncTcpConnection extends TcpConnection
         }
         // If failed attempt to emit onError callback.
         if (!$this->_socket || !\is_resource($this->_socket)) {
-            $this->emitError(\WORKERMAN_CONNECT_FAIL, $errstr);
+            $this->emitError(static::CONNECT_FAIL, $errstr);
             if ($this->_status === self::STATUS_CLOSING) {
                 $this->destroy();
             }
@@ -210,10 +211,10 @@ class AsyncTcpConnection extends TcpConnection
             return;
         }
         // Add socket to global event loop waiting connection is successfully established or faild.
-        Worker::$globalEvent->add($this->_socket, EventInterface::EV_WRITE, array($this, 'checkConnection'));
+        Worker::$globalEvent->onWritable($this->_socket, [$this, 'checkConnection']);
         // For windows.
-        if(\DIRECTORY_SEPARATOR === '\\') {
-            Worker::$globalEvent->add($this->_socket, EventInterface::EV_EXCEPT, array($this, 'checkConnection'));
+        if (\DIRECTORY_SEPARATOR === '\\') {
+            Worker::$globalEvent->onExcept($this->_socket, [$this, 'checkConnection']);
         }
     }
 
@@ -225,13 +226,13 @@ class AsyncTcpConnection extends TcpConnection
      */
     public function reconnect($after = 0)
     {
-        $this->_status                   = self::STATUS_INITIAL;
+        $this->_status = self::STATUS_INITIAL;
         static::$connections[$this->_id] = $this;
         if ($this->_reconnectTimer) {
             Timer::del($this->_reconnectTimer);
         }
         if ($after > 0) {
-            $this->_reconnectTimer = Timer::add($after, array($this, 'connect'), null, false);
+            $this->_reconnectTimer = Timer::add($after, [$this, 'connect'], null, false);
             return;
         }
         $this->connect();
@@ -270,7 +271,7 @@ class AsyncTcpConnection extends TcpConnection
     /**
      * Try to emit onError callback.
      *
-     * @param int    $code
+     * @param int $code
      * @param string $msg
      * @return void
      */
@@ -279,10 +280,8 @@ class AsyncTcpConnection extends TcpConnection
         $this->_status = self::STATUS_CLOSING;
         if ($this->onError) {
             try {
-                \call_user_func($this->onError, $this, $code, $msg);
-            } catch (\Exception $e) {
-                Worker::stopAll(250, $e);
-            } catch (\Error $e) {
+                ($this->onError)($this, $code, $msg);
+            } catch (\Throwable $e) {
                 Worker::stopAll(250, $e);
             }
         }
@@ -297,12 +296,12 @@ class AsyncTcpConnection extends TcpConnection
     public function checkConnection()
     {
         // Remove EV_EXPECT for windows.
-        if(\DIRECTORY_SEPARATOR === '\\') {
-            Worker::$globalEvent->del($this->_socket, EventInterface::EV_EXCEPT);
+        if (\DIRECTORY_SEPARATOR === '\\') {
+            Worker::$globalEvent->offExcept($this->_socket);
         }
 
         // Remove write listener.
-        Worker::$globalEvent->del($this->_socket, EventInterface::EV_WRITE);
+        Worker::$globalEvent->offWritable($this->_socket);
 
         if ($this->_status !== self::STATUS_CONNECTING) {
             return;
@@ -332,39 +331,35 @@ class AsyncTcpConnection extends TcpConnection
             } else {
                 // There are some data waiting to send.
                 if ($this->_sendBuffer) {
-                    Worker::$globalEvent->add($this->_socket, EventInterface::EV_WRITE, array($this, 'baseWrite'));
+                    Worker::$globalEvent->onWritable($this->_socket, [$this, 'baseWrite']);
                 }
             }
 
             // Register a listener waiting read event.
-            Worker::$globalEvent->add($this->_socket, EventInterface::EV_READ, array($this, 'baseRead'));
+            Worker::$globalEvent->onReadable($this->_socket, [$this, 'baseRead']);
 
-            $this->_status                = self::STATUS_ESTABLISHED;
-            $this->_remoteAddress         = $address;
+            $this->_status = self::STATUS_ESTABLISHED;
+            $this->_remoteAddress = $address;
 
             // Try to emit onConnect callback.
             if ($this->onConnect) {
                 try {
-                    \call_user_func($this->onConnect, $this);
-                } catch (\Exception $e) {
-                    Worker::stopAll(250, $e);
-                } catch (\Error $e) {
+                    ($this->onConnect)($this);
+                } catch (\Throwable $e) {
                     Worker::stopAll(250, $e);
                 }
             }
             // Try to emit protocol::onConnect
             if ($this->protocol && \method_exists($this->protocol, 'onConnect')) {
                 try {
-                    \call_user_func(array($this->protocol, 'onConnect'), $this);
-                } catch (\Exception $e) {
-                    Worker::stopAll(250, $e);
-                } catch (\Error $e) {
+                    [$this->protocol, 'onConnect']($this);
+                } catch (\Throwable $e) {
                     Worker::stopAll(250, $e);
                 }
             }
         } else {
             // Connection failed.
-            $this->emitError(\WORKERMAN_CONNECT_FAIL, 'connect ' . $this->_remoteAddress . ' fail after ' . round(\microtime(true) - $this->_connectStartTime, 4) . ' seconds');
+            $this->emitError(static::CONNECT_FAIL, 'connect ' . $this->_remoteAddress . ' fail after ' . round(\microtime(true) - $this->_connectStartTime, 4) . ' seconds');
             if ($this->_status === self::STATUS_CLOSING) {
                 $this->destroy();
             }

+ 20 - 26
Connection/AsyncUdpConnection.php → src/Connection/AsyncUdpConnection.php

@@ -11,6 +11,7 @@
  * @link      http://www.workerman.net/
  * @license   http://www.opensource.org/licenses/mit-license.php MIT License
  */
+
 namespace Workerman\Connection;
 
 use Workerman\Events\EventInterface;
@@ -62,7 +63,7 @@ class AsyncUdpConnection extends UdpConnection
         list($scheme, $address) = \explode(':', $remote_address, 2);
         // Check application layer protocol class.
         if ($scheme !== 'udp') {
-            $scheme         = \ucfirst($scheme);
+            $scheme = \ucfirst($scheme);
             $this->protocol = '\\Protocols\\' . $scheme;
             if (!\class_exists($this->protocol)) {
                 $this->protocol = "\\Workerman\\Protocols\\$scheme";
@@ -71,11 +72,11 @@ class AsyncUdpConnection extends UdpConnection
                 }
             }
         }
-        
+
         $this->_remoteAddress = \substr($address, 2);
         $this->_contextOption = $context_option;
     }
-    
+
     /**
      * For udp package.
      *
@@ -88,18 +89,15 @@ class AsyncUdpConnection extends UdpConnection
         if (false === $recv_buffer || empty($remote_address)) {
             return false;
         }
-        
+
         if ($this->onMessage) {
             if ($this->protocol) {
-                $parser      = $this->protocol;
-                $recv_buffer = $parser::decode($recv_buffer, $this);
+                $recv_buffer = $this->protocol::decode($recv_buffer, $this);
             }
             ++ConnectionInterface::$statistics['total_request'];
             try {
-                \call_user_func($this->onMessage, $this, $recv_buffer);
-            } catch (\Exception $e) {
-                Worker::stopAll(250, $e);
-            } catch (\Error $e) {
+                ($this->onMessage)($this, $recv_buffer);
+            } catch (\Throwable $e) {
                 Worker::stopAll(250, $e);
             }
         }
@@ -110,13 +108,13 @@ class AsyncUdpConnection extends UdpConnection
      * Sends data on the connection.
      *
      * @param string $send_buffer
-     * @param bool   $raw
+     * @param bool $raw
      * @return void|boolean
      */
     public function send($send_buffer, $raw = false)
     {
         if (false === $raw && $this->protocol) {
-            $parser      = $this->protocol;
+            $parser = $this->protocol;
             $send_buffer = $parser::encode($send_buffer, $this);
             if ($send_buffer === '') {
                 return;
@@ -127,8 +125,8 @@ class AsyncUdpConnection extends UdpConnection
         }
         return \strlen($send_buffer) === \stream_socket_sendto($this->_socket, $send_buffer, 0);
     }
-    
-    
+
+
     /**
      * Close connection.
      *
@@ -142,16 +140,14 @@ class AsyncUdpConnection extends UdpConnection
         if ($data !== null) {
             $this->send($data, $raw);
         }
-        Worker::$globalEvent->del($this->_socket, EventInterface::EV_READ);
+        Worker::$globalEvent->offReadable($this->_socket);
         \fclose($this->_socket);
         $this->connected = false;
         // Try to emit onClose callback.
         if ($this->onClose) {
             try {
-                \call_user_func($this->onClose, $this);
-            } catch (\Exception $e) {
-                Worker::stopAll(250, $e);
-            } catch (\Error $e) {
+                ($this->onClose)($this);
+            } catch (\Throwable $e) {
                 Worker::stopAll(250, $e);
             }
         }
@@ -181,20 +177,18 @@ class AsyncUdpConnection extends UdpConnection
             Worker::safeEcho(new \Exception($errmsg));
             return;
         }
-        
+
         \stream_set_blocking($this->_socket, false);
-        
+
         if ($this->onMessage) {
-            Worker::$globalEvent->add($this->_socket, EventInterface::EV_READ, array($this, 'baseRead'));
+            Worker::$globalEvent->add($this->_socket, EventInterface::EV_READ, [$this, 'baseRead']);
         }
         $this->connected = true;
         // Try to emit onConnect callback.
         if ($this->onConnect) {
             try {
-                \call_user_func($this->onConnect, $this);
-            } catch (\Exception $e) {
-                Worker::stopAll(250, $e);
-            } catch (\Error $e) {
+                ($this->onConnect)($this);
+            } catch (\Throwable $e) {
                 Worker::stopAll(250, $e);
             }
         }

+ 28 - 6
Connection/ConnectionInterface.php → src/Connection/ConnectionInterface.php

@@ -11,24 +11,39 @@
  * @link      http://www.workerman.net/
  * @license   http://www.opensource.org/licenses/mit-license.php MIT License
  */
+
 namespace Workerman\Connection;
 
 /**
  * ConnectionInterface.
  */
-abstract class  ConnectionInterface
+abstract class ConnectionInterface
 {
     /**
+     * Connect failed.
+     *
+     * @var int
+     */
+    const CONNECT_FAIL = 1;
+
+    /**
+     * Send failed.
+     *
+     * @var int
+     */
+    const SEND_FAIL = 2;
+
+    /**
      * Statistics for status command.
      *
      * @var array
      */
-    public static $statistics = array(
+    public static $statistics = [
         'connection_count' => 0,
-        'total_request'    => 0,
-        'throw_exception'  => 0,
-        'send_fail'        => 0,
-    );
+        'total_request' => 0,
+        'throw_exception' => 0,
+        'send_fail' => 0,
+    ];
 
     /**
      * Emitted when data is received.
@@ -52,6 +67,13 @@ abstract class  ConnectionInterface
     public $onError = null;
 
     /**
+     * Protocol context
+     *
+     * @var array
+     */
+    public $protocolContext = [];
+
+    /**
      * Sends data on the connection.
      *
      * @param mixed $send_buffer

+ 126 - 104
Connection/TcpConnection.php → src/Connection/TcpConnection.php

@@ -11,11 +11,12 @@
  * @link      http://www.workerman.net/
  * @license   http://www.opensource.org/licenses/mit-license.php MIT License
  */
+
 namespace Workerman\Connection;
 
 use Workerman\Events\EventInterface;
+use Workerman\Protocols\Http\Request;
 use Workerman\Worker;
-use \Exception;
 
 /**
  * TcpConnection.
@@ -27,7 +28,7 @@ class TcpConnection extends ConnectionInterface
      *
      * @var int
      */
-    const READ_BUFFER_SIZE = 65535;
+    const READ_BUFFER_SIZE = 87380;
 
     /**
      * Status initial.
@@ -170,7 +171,7 @@ class TcpConnection extends ConnectionInterface
      * @var int
      */
     public $maxPackageSize = 1048576;
-    
+
     /**
      * Default maximum acceptable packet size.
      *
@@ -186,6 +187,13 @@ class TcpConnection extends ConnectionInterface
     protected static $_idRecorder = 1;
 
     /**
+     * Cache.
+     *
+     * @var bool.
+     */
+    protected static $_enableCache = true;
+
+    /**
      * Socket
      *
      * @var resource
@@ -246,32 +254,32 @@ class TcpConnection extends ConnectionInterface
      *
      * @var array
      */
-    public static $connections = array();
+    public static $connections = [];
 
     /**
      * Status to string.
      *
      * @var array
      */
-    public static $_statusToString = array(
-        self::STATUS_INITIAL     => 'INITIAL',
-        self::STATUS_CONNECTING  => 'CONNECTING',
+    public static $_statusToString = [
+        self::STATUS_INITIAL => 'INITIAL',
+        self::STATUS_CONNECTING => 'CONNECTING',
         self::STATUS_ESTABLISHED => 'ESTABLISHED',
-        self::STATUS_CLOSING     => 'CLOSING',
-        self::STATUS_CLOSED      => 'CLOSED',
-    );
+        self::STATUS_CLOSING => 'CLOSING',
+        self::STATUS_CLOSED => 'CLOSED',
+    ];
 
     /**
      * Construct.
      *
      * @param resource $socket
-     * @param string   $remote_address
+     * @param string $remote_address
      */
     public function __construct($socket, $remote_address = '')
     {
         ++self::$statistics['connection_count'];
         $this->id = $this->_id = self::$_idRecorder++;
-        if(self::$_idRecorder === \PHP_INT_MAX){
+        if (self::$_idRecorder === \PHP_INT_MAX) {
             self::$_idRecorder = 0;
         }
         $this->_socket = $socket;
@@ -280,10 +288,10 @@ class TcpConnection extends ConnectionInterface
         if (\function_exists('stream_set_read_buffer')) {
             \stream_set_read_buffer($this->_socket, 0);
         }
-        Worker::$globalEvent->add($this->_socket, EventInterface::EV_READ, array($this, 'baseRead'));
-        $this->maxSendBufferSize        = self::$defaultMaxSendBufferSize;
-        $this->maxPackageSize           = self::$defaultMaxPackageSize;
-        $this->_remoteAddress           = $remote_address;
+        Worker::$globalEvent->onReadable($this->_socket, [$this, 'baseRead']);
+        $this->maxSendBufferSize = self::$defaultMaxSendBufferSize;
+        $this->maxPackageSize = self::$defaultMaxPackageSize;
+        $this->_remoteAddress = $remote_address;
         static::$connections[$this->id] = $this;
     }
 
@@ -306,7 +314,7 @@ class TcpConnection extends ConnectionInterface
      * Sends data on the connection.
      *
      * @param mixed $send_buffer
-     * @param bool  $raw
+     * @param bool $raw
      * @return bool|null
      */
     public function send($send_buffer, $raw = false)
@@ -317,8 +325,7 @@ class TcpConnection extends ConnectionInterface
 
         // Try to call protocol::encode($send_buffer) before sending.
         if (false === $raw && $this->protocol !== null) {
-            $parser      = $this->protocol;
-            $send_buffer = $parser::encode($send_buffer, $this);
+            $send_buffer = $this->protocol::encode($send_buffer, $this);
             if ($send_buffer === '') {
                 return;
             }
@@ -339,7 +346,7 @@ class TcpConnection extends ConnectionInterface
         // Attempt to send data directly.
         if ($this->_sendBuffer === '') {
             if ($this->transport === 'ssl') {
-                Worker::$globalEvent->add($this->_socket, EventInterface::EV_WRITE, array($this, 'baseWrite'));
+                Worker::$globalEvent->onWritable($this->_socket, [$this, 'baseWrite']);
                 $this->_sendBuffer = $send_buffer;
                 $this->checkBufferWillFull();
                 return;
@@ -347,9 +354,7 @@ class TcpConnection extends ConnectionInterface
             $len = 0;
             try {
                 $len = @\fwrite($this->_socket, $send_buffer);
-            } catch (\Exception $e) {
-                Worker::log($e);
-            } catch (\Error $e) {
+            } catch (\Throwable $e) {
                 Worker::log($e);
             }
             // send successful.
@@ -367,10 +372,8 @@ class TcpConnection extends ConnectionInterface
                     ++self::$statistics['send_fail'];
                     if ($this->onError) {
                         try {
-                            \call_user_func($this->onError, $this, \WORKERMAN_SEND_FAIL, 'client closed');
-                        } catch (\Exception $e) {
-                            Worker::stopAll(250, $e);
-                        } catch (\Error $e) {
+                            ($this->onError)($this, static::SEND_FAIL, 'client closed');
+                        } catch (\Throwable $e) {
                             Worker::stopAll(250, $e);
                         }
                     }
@@ -379,7 +382,7 @@ class TcpConnection extends ConnectionInterface
                 }
                 $this->_sendBuffer = $send_buffer;
             }
-            Worker::$globalEvent->add($this->_socket, EventInterface::EV_WRITE, array($this, 'baseWrite'));
+            Worker::$globalEvent->onWritable($this->_socket, [$this, 'baseWrite']);
             // Check if the send buffer will be full.
             $this->checkBufferWillFull();
             return;
@@ -404,7 +407,7 @@ class TcpConnection extends ConnectionInterface
     {
         $pos = \strrpos($this->_remoteAddress, ':');
         if ($pos) {
-            return (string) \substr($this->_remoteAddress, 0, $pos);
+            return (string)\substr($this->_remoteAddress, 0, $pos);
         }
         return '';
     }
@@ -417,7 +420,7 @@ class TcpConnection extends ConnectionInterface
     public function getRemotePort()
     {
         if ($this->_remoteAddress) {
-            return (int) \substr(\strrchr($this->_remoteAddress, ':'), 1);
+            return (int)\substr(\strrchr($this->_remoteAddress, ':'), 1);
         }
         return 0;
     }
@@ -528,7 +531,7 @@ class TcpConnection extends ConnectionInterface
      */
     public function pauseRecv()
     {
-        Worker::$globalEvent->del($this->_socket, EventInterface::EV_READ);
+        Worker::$globalEvent->offReadable($this->_socket);
         $this->_isPaused = true;
     }
 
@@ -540,14 +543,13 @@ class TcpConnection extends ConnectionInterface
     public function resumeRecv()
     {
         if ($this->_isPaused === true) {
-            Worker::$globalEvent->add($this->_socket, EventInterface::EV_READ, array($this, 'baseRead'));
+            Worker::$globalEvent->onReadable($this->_socket, [$this, 'baseRead']);
             $this->_isPaused = false;
             $this->baseRead($this->_socket, false);
         }
     }
 
 
-
     /**
      * Base read handler.
      *
@@ -557,12 +559,13 @@ class TcpConnection extends ConnectionInterface
      */
     public function baseRead($socket, $check_eof = true)
     {
+        static $requests = [];
         // SSL handshake.
         if ($this->transport === 'ssl' && $this->_sslHandshakeCompleted !== true) {
             if ($this->doSslHandshake($socket)) {
                 $this->_sslHandshakeCompleted = true;
                 if ($this->_sendBuffer) {
-                    Worker::$globalEvent->add($socket, EventInterface::EV_WRITE, array($this, 'baseWrite'));
+                    Worker::$globalEvent->onWritable($socket, [$this, 'baseWrite']);
                 }
             } else {
                 return;
@@ -572,7 +575,8 @@ class TcpConnection extends ConnectionInterface
         $buffer = '';
         try {
             $buffer = @\fread($socket, self::READ_BUFFER_SIZE);
-        } catch (\Exception $e) {} catch (\Error $e) {}
+        } catch (\Throwable $e) {
+        }
 
         // Check connection closed.
         if ($buffer === '' || $buffer === false) {
@@ -582,12 +586,32 @@ class TcpConnection extends ConnectionInterface
             }
         } else {
             $this->bytesRead += \strlen($buffer);
-            $this->_recvBuffer .= $buffer;
+            if ($this->_recvBuffer === '') {
+                if (static::$_enableCache && !isset($requests[512]) && isset($requests[$buffer])) {
+                    ++self::$statistics['total_request'];
+                    $request = $requests[$buffer];
+                    if ($request instanceof Request) {
+                        $request = clone $request;
+                        $requests[$buffer] = $request;
+                        $request->connection = $this;
+                        $this->__request = $request;
+                        $request->properties = [];
+                    }
+                    try {
+                        ($this->onMessage)($this, $request);
+                    } catch (\Throwable $e) {
+                        Worker::stopAll(250, $e);
+                    }
+                    return;
+                }
+                $this->_recvBuffer = $buffer;
+            } else {
+                $this->_recvBuffer .= $buffer;
+            }
         }
 
         // If the application layer protocol has been set up.
         if ($this->protocol !== null) {
-            $parser = $this->protocol;
             while ($this->_recvBuffer !== '' && !$this->_isPaused) {
                 // The current packet length is known.
                 if ($this->_currentPackageLength) {
@@ -598,8 +622,9 @@ class TcpConnection extends ConnectionInterface
                 } else {
                     // Get current package length.
                     try {
-                        $this->_currentPackageLength = $parser::input($this->_recvBuffer, $this);
-                    } catch (\Exception $e) {} catch (\Error $e) {}
+                        $this->_currentPackageLength = $this->protocol::input($this->_recvBuffer, $this);
+                    } catch (\Throwable $e) {
+                    }
                     // The packet length is unknown.
                     if ($this->_currentPackageLength === 0) {
                         break;
@@ -619,9 +644,9 @@ class TcpConnection extends ConnectionInterface
                 // The data is enough for a packet.
                 ++self::$statistics['total_request'];
                 // The current packet length is equal to the length of the buffer.
-                if (\strlen($this->_recvBuffer) === $this->_currentPackageLength) {
+                if ($one = \strlen($this->_recvBuffer) === $this->_currentPackageLength) {
                     $one_request_buffer = $this->_recvBuffer;
-                    $this->_recvBuffer  = '';
+                    $this->_recvBuffer = '';
                 } else {
                     // Get a full package from the buffer.
                     $one_request_buffer = \substr($this->_recvBuffer, 0, $this->_currentPackageLength);
@@ -630,15 +655,17 @@ class TcpConnection extends ConnectionInterface
                 }
                 // Reset the current packet length to 0.
                 $this->_currentPackageLength = 0;
-                if (!$this->onMessage) {
-                    continue;
-                }
                 try {
                     // Decode request buffer before Emitting onMessage callback.
-                    \call_user_func($this->onMessage, $this, $parser::decode($one_request_buffer, $this));
-                } catch (\Exception $e) {
-                    Worker::stopAll(250, $e);
-                } catch (\Error $e) {
+                    $request = $this->protocol::decode($one_request_buffer, $this);
+                    if (static::$_enableCache && (!\is_object($request) || $request instanceof Request) && $one && !isset($one_request_buffer[512])) {
+                        $requests[$one_request_buffer] = $request;
+                        if (\count($requests) > 512) {
+                            unset($requests[\key($requests)]);
+                        }
+                    }
+                    ($this->onMessage)($this, $request);
+                } catch (\Throwable $e) {
                     Worker::stopAll(250, $e);
                 }
             }
@@ -651,15 +678,9 @@ class TcpConnection extends ConnectionInterface
 
         // Applications protocol is not set.
         ++self::$statistics['total_request'];
-        if (!$this->onMessage) {
-            $this->_recvBuffer = '';
-            return;
-        }
         try {
-            \call_user_func($this->onMessage, $this, $this->_recvBuffer);
-        } catch (\Exception $e) {
-            Worker::stopAll(250, $e);
-        } catch (\Error $e) {
+            ($this->onMessage)($this, $this->_recvBuffer);
+        } catch (\Throwable $e) {
             Worker::stopAll(250, $e);
         }
         // Clean receive buffer.
@@ -673,7 +694,8 @@ class TcpConnection extends ConnectionInterface
      */
     public function baseWrite()
     {
-        \set_error_handler(function(){});
+        \set_error_handler(function () {
+        });
         if ($this->transport === 'ssl') {
             $len = @\fwrite($this->_socket, $this->_sendBuffer, 8192);
         } else {
@@ -682,15 +704,13 @@ class TcpConnection extends ConnectionInterface
         \restore_error_handler();
         if ($len === \strlen($this->_sendBuffer)) {
             $this->bytesWritten += $len;
-            Worker::$globalEvent->del($this->_socket, EventInterface::EV_WRITE);
+            Worker::$globalEvent->offWritable($this->_socket);
             $this->_sendBuffer = '';
             // Try to emit onBufferDrain callback when the send buffer becomes empty.
             if ($this->onBufferDrain) {
                 try {
-                    \call_user_func($this->onBufferDrain, $this);
-                } catch (\Exception $e) {
-                    Worker::stopAll(250, $e);
-                } catch (\Error $e) {
+                    ($this->onBufferDrain)($this);
+                } catch (\Throwable $e) {
                     Worker::stopAll(250, $e);
                 }
             }
@@ -714,31 +734,32 @@ class TcpConnection extends ConnectionInterface
      * @param resource $socket
      * @return bool
      */
-    public function doSslHandshake($socket){
+    public function doSslHandshake($socket)
+    {
         if (\feof($socket)) {
             $this->destroy();
             return false;
         }
         $async = $this instanceof AsyncTcpConnection;
-        
+
         /**
-          *  We disabled ssl3 because https://blog.qualys.com/ssllabs/2014/10/15/ssl-3-is-dead-killed-by-the-poodle-attack.
-          *  You can enable ssl3 by the codes below.
-          */
+         *  We disabled ssl3 because https://blog.qualys.com/ssllabs/2014/10/15/ssl-3-is-dead-killed-by-the-poodle-attack.
+         *  You can enable ssl3 by the codes below.
+         */
         /*if($async){
             $type = STREAM_CRYPTO_METHOD_SSLv2_CLIENT | STREAM_CRYPTO_METHOD_SSLv23_CLIENT | STREAM_CRYPTO_METHOD_SSLv3_CLIENT;
         }else{
             $type = STREAM_CRYPTO_METHOD_SSLv2_SERVER | STREAM_CRYPTO_METHOD_SSLv23_SERVER | STREAM_CRYPTO_METHOD_SSLv3_SERVER;
         }*/
-        
-        if($async){
+
+        if ($async) {
             $type = \STREAM_CRYPTO_METHOD_SSLv2_CLIENT | \STREAM_CRYPTO_METHOD_SSLv23_CLIENT;
-        }else{
+        } else {
             $type = \STREAM_CRYPTO_METHOD_SSLv2_SERVER | \STREAM_CRYPTO_METHOD_SSLv23_SERVER;
         }
-        
+
         // Hidden error.
-        \set_error_handler(function($errno, $errstr, $file){
+        \set_error_handler(function ($errno, $errstr, $file) {
             if (!Worker::$daemonize) {
                 Worker::safeEcho("SSL handshake error: $errstr \n");
             }
@@ -755,10 +776,8 @@ class TcpConnection extends ConnectionInterface
         }
         if (isset($this->onSslHandshake)) {
             try {
-                \call_user_func($this->onSslHandshake, $this);
-            } catch (\Exception $e) {
-                Worker::stopAll(250, $e);
-            } catch (\Error $e) {
+                ($this->onSslHandshake)($this);
+            } catch (\Throwable $e) {
                 Worker::stopAll(250, $e);
             }
         }
@@ -773,14 +792,14 @@ class TcpConnection extends ConnectionInterface
      */
     public function pipe(self $dest)
     {
-        $source              = $this;
-        $this->onMessage     = function ($source, $data) use ($dest) {
+        $source = $this;
+        $this->onMessage = function ($source, $data) use ($dest) {
             $dest->send($data);
         };
-        $this->onClose       = function ($source) use ($dest) {
+        $this->onClose = function ($source) use ($dest) {
             $dest->close();
         };
-        $dest->onBufferFull  = function ($dest) use ($source) {
+        $dest->onBufferFull = function ($dest) use ($source) {
             $source->pauseRecv();
         };
         $dest->onBufferDrain = function ($dest) use ($source) {
@@ -808,7 +827,7 @@ class TcpConnection extends ConnectionInterface
      */
     public function close($data = null, $raw = false)
     {
-        if($this->_status === self::STATUS_CONNECTING){
+        if ($this->_status === self::STATUS_CONNECTING) {
             $this->destroy();
             return;
         }
@@ -822,7 +841,7 @@ class TcpConnection extends ConnectionInterface
         }
 
         $this->_status = self::STATUS_CLOSING;
-        
+
         if ($this->_sendBuffer === '') {
             $this->destroy();
         } else {
@@ -850,10 +869,8 @@ class TcpConnection extends ConnectionInterface
         if ($this->maxSendBufferSize <= \strlen($this->_sendBuffer)) {
             if ($this->onBufferFull) {
                 try {
-                    \call_user_func($this->onBufferFull, $this);
-                } catch (\Exception $e) {
-                    Worker::stopAll(250, $e);
-                } catch (\Error $e) {
+                    ($this->onBufferFull)($this);
+                } catch (\Throwable $e) {
                     Worker::stopAll(250, $e);
                 }
             }
@@ -871,10 +888,8 @@ class TcpConnection extends ConnectionInterface
         if ($this->maxSendBufferSize <= \strlen($this->_sendBuffer)) {
             if ($this->onError) {
                 try {
-                    \call_user_func($this->onError, $this, \WORKERMAN_SEND_FAIL, 'send buffer full and drop package');
-                } catch (\Exception $e) {
-                    Worker::stopAll(250, $e);
-                } catch (\Error $e) {
+                    ($this->onError)($this, static::SEND_FAIL, 'send buffer full and drop package');
+                } catch (\Throwable $e) {
                     Worker::stopAll(250, $e);
                 }
             }
@@ -882,7 +897,7 @@ class TcpConnection extends ConnectionInterface
         }
         return false;
     }
-    
+
     /**
      * Whether send buffer is Empty.
      *
@@ -890,7 +905,7 @@ class TcpConnection extends ConnectionInterface
      */
     public function bufferIsEmpty()
     {
-    	return empty($this->_sendBuffer);
+        return empty($this->_sendBuffer);
     }
 
     /**
@@ -905,32 +920,29 @@ class TcpConnection extends ConnectionInterface
             return;
         }
         // Remove event listener.
-        Worker::$globalEvent->del($this->_socket, EventInterface::EV_READ);
-        Worker::$globalEvent->del($this->_socket, EventInterface::EV_WRITE);
+        Worker::$globalEvent->offReadable($this->_socket);
+        Worker::$globalEvent->offWritable($this->_socket);
 
         // Close socket.
         try {
             @\fclose($this->_socket);
-        } catch (\Exception $e) {} catch (\Error $e) {}
+        } catch (\Throwable $e) {
+        }
 
         $this->_status = self::STATUS_CLOSED;
         // Try to emit onClose callback.
         if ($this->onClose) {
             try {
-                \call_user_func($this->onClose, $this);
-            } catch (\Exception $e) {
-                Worker::stopAll(250, $e);
-            } catch (\Error $e) {
+                ($this->onClose)($this);
+            } catch (\Throwable $e) {
                 Worker::stopAll(250, $e);
             }
         }
         // Try to emit protocol::onClose
         if ($this->protocol && \method_exists($this->protocol, 'onClose')) {
             try {
-                \call_user_func(array($this->protocol, 'onClose'), $this);
-            } catch (\Exception $e) {
-                Worker::stopAll(250, $e);
-            } catch (\Error $e) {
+                ([$this->protocol, 'onClose'])($this);
+            } catch (\Throwable $e) {
                 Worker::stopAll(250, $e);
             }
         }
@@ -949,6 +961,16 @@ class TcpConnection extends ConnectionInterface
     }
 
     /**
+     * Enable or disable Cache.
+     *
+     * @param mixed $value
+     */
+    public static function enableCache($value)
+    {
+        static::$_enableCache = (bool)$value;
+    }
+
+    /**
      * Destruct.
      *
      * @return void
@@ -966,7 +988,7 @@ class TcpConnection extends ConnectionInterface
                 Worker::log('worker[' . \posix_getpid() . '] remains ' . self::$statistics['connection_count'] . ' connection(s)');
             }
 
-            if(0 === self::$statistics['connection_count']) {
+            if (0 === self::$statistics['connection_count']) {
                 Worker::stopAll();
             }
         }

+ 7 - 6
Connection/UdpConnection.php → src/Connection/UdpConnection.php

@@ -11,6 +11,7 @@
  * @link      http://www.workerman.net/
  * @license   http://www.opensource.org/licenses/mit-license.php MIT License
  */
+
 namespace Workerman\Connection;
 
 /**
@@ -51,11 +52,11 @@ class UdpConnection extends ConnectionInterface
      * Construct.
      *
      * @param resource $socket
-     * @param string   $remote_address
+     * @param string $remote_address
      */
     public function __construct($socket, $remote_address)
     {
-        $this->_socket        = $socket;
+        $this->_socket = $socket;
         $this->_remoteAddress = $remote_address;
     }
 
@@ -63,13 +64,13 @@ class UdpConnection extends ConnectionInterface
      * Sends data on the connection.
      *
      * @param string $send_buffer
-     * @param bool   $raw
+     * @param bool $raw
      * @return void|boolean
      */
     public function send($send_buffer, $raw = false)
     {
         if (false === $raw && $this->protocol) {
-            $parser      = $this->protocol;
+            $parser = $this->protocol;
             $send_buffer = $parser::encode($send_buffer, $this);
             if ($send_buffer === '') {
                 return;
@@ -185,7 +186,7 @@ class UdpConnection extends ConnectionInterface
      * Close connection.
      *
      * @param mixed $data
-     * @param bool  $raw
+     * @param bool $raw
      * @return bool
      */
     public function close($data = null, $raw = false)
@@ -195,7 +196,7 @@ class UdpConnection extends ConnectionInterface
         }
         return true;
     }
-    
+
     /**
      * Get the real socket.
      *

+ 203 - 0
src/Events/Ev.php

@@ -0,0 +1,203 @@
+<?php
+/**
+ * This file is part of workerman.
+ *
+ * Licensed under The MIT License
+ * For full copyright and license information, please see the MIT-LICENSE.txt
+ * Redistributions of files must retain the above copyright notice.
+ *
+ * @author  walkor<walkor@workerman.net>
+ * @link    http://www.workerman.net/
+ * @license http://www.opensource.org/licenses/mit-license.php MIT License
+ */
+
+namespace Workerman\Events;
+
+use Workerman\Worker;
+use \EvWatcher;
+
+/**
+ * Ev eventloop
+ */
+class Ev implements EventInterface
+{
+    /**
+     * All listeners for read event.
+     *
+     * @var array
+     */
+    protected $_readEvents = [];
+
+    /**
+     * All listeners for write event.
+     *
+     * @var array
+     */
+    protected $_writeEvents = [];
+
+    /**
+     * Event listeners of signal.
+     *
+     * @var array
+     */
+    protected $_eventSignal = [];
+
+    /**
+     * All timer event listeners.
+     *
+     * @var array
+     */
+    protected $_eventTimer = [];
+
+    /**
+     * Timer id.
+     *
+     * @var int
+     */
+    protected static $_timerId = 1;
+
+    /**
+     * {@inheritdoc}
+     */
+    public function delay(float $delay, $func, $args)
+    {
+        $timer_id = self::$_timerId;
+        $event = new \EvTimer($delay, 0, function () use ($func, $args, $timer_id) {
+            unset($this->_eventTimer[$timer_id]);
+            $func(...(array)$args);
+        });
+        $this->_eventTimer[self::$_timerId] = $event;
+        return self::$_timerId++;
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function deleteTimer($timer_id)
+    {
+        if (isset($this->_eventTimer[$timer_id])) {
+            $this->_eventTimer[$timer_id]->stop();
+            unset($this->_eventTimer[$timer_id]);
+            return true;
+        }
+        return false;
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function repeat(float $interval, $func, $args)
+    {
+        $event = new \EvTimer($interval, $interval, function () use ($func, $args) {
+            $func(...(array)$args);
+        });
+        $this->_eventTimer[self::$_timerId] = $event;
+        return self::$_timerId++;
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function onReadable($stream, $func)
+    {
+        $fd_key = (int)$stream;
+        $event = new \EvIo($stream, \Ev::READ, function () use ($func, $stream) {
+            $func($stream);
+        });
+        $this->_readEvents[$fd_key] = $event;
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function offReadable($stream)
+    {
+        $fd_key = (int)$stream;
+        if (isset($this->_readEvents[$fd_key])) {
+            $this->_readEvents[$fd_key]->stop();
+            unset($this->_readEvents[$fd_key]);
+        }
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function onWritable($stream, $func)
+    {
+        $fd_key = (int)$stream;
+        $event = new \EvIo($stream, \Ev::WRITE, function () use ($func, $stream) {
+            $func($stream);
+        });
+        $this->_readEvents[$fd_key] = $event;
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function offWritable($stream)
+    {
+        $fd_key = (int)$stream;
+        if (isset($this->_writeEvents[$fd_key])) {
+            $this->_writeEvents[$fd_key]->stop();
+            unset($this->_writeEvents[$fd_key]);
+        }
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function onSignal($signal, $func)
+    {
+        $event = new \EvSignal($signal, function () use ($func, $signal) {
+            $func($signal);
+        });
+        $this->_eventSignal[$signal] = $event;
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function offSignal($signal)
+    {
+        if (isset($this->_eventSignal[$signal])) {
+            $this->_eventSignal[$signal]->stop();
+            unset($this->_eventSignal[$signal]);
+        }
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function deleteAllTimer()
+    {
+        foreach ($this->_eventTimer as $event) {
+            $event->stop();
+        }
+        $this->_eventTimer = [];
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function run()
+    {
+        \Ev::run();
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function stop()
+    {
+        \Ev::stop();
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function getTimerCount()
+    {
+        return \count($this->_eventTimer);
+    }
+
+}

+ 255 - 0
src/Events/Event.php

@@ -0,0 +1,255 @@
+<?php
+/**
+ * This file is part of workerman.
+ *
+ * Licensed under The MIT License
+ * For full copyright and license information, please see the MIT-LICENSE.txt
+ * Redistributions of files must retain the above copyright notice.
+ *
+ * @author    walkor<walkor@workerman.net>
+ * @copyright walkor<walkor@workerman.net>
+ * @link      http://www.workerman.net/
+ * @license   http://www.opensource.org/licenses/mit-license.php MIT License
+ */
+
+namespace Workerman\Events;
+
+use Workerman\Worker;
+
+/**
+ * libevent eventloop
+ */
+class Event implements EventInterface
+{
+    /**
+     * Event base.
+     * @var object
+     */
+    protected $_eventBase = null;
+
+    /**
+     * All listeners for read event.
+     * @var array
+     */
+    protected $_readEvents = [];
+
+    /**
+     * All listeners for write event.
+     * @var array
+     */
+    protected $_writeEvents = [];
+
+    /**
+     * Event listeners of signal.
+     * @var array
+     */
+    protected $_eventSignal = [];
+
+    /**
+     * All timer event listeners.
+     * [func, args, event, flag, time_interval]
+     * @var array
+     */
+    protected $_eventTimer = [];
+
+    /**
+     * Timer id.
+     * @var int
+     */
+    protected $_timerId = 1;
+
+    /**
+     * Event class name.
+     * @var string
+     */
+    protected $_eventClassName = '';
+
+    /**
+     * Construct.
+     * @return void
+     */
+    public function __construct()
+    {
+        if (\class_exists('\\\\Event', false)) {
+            $class_name = '\\\\Event';
+        } else {
+            $class_name = '\Event';
+        }
+        $this->_eventClassName = $class_name;
+        if (\class_exists('\\\\EventBase', false)) {
+            $class_name = '\\\\EventBase';
+        } else {
+            $class_name = '\EventBase';
+        }
+        $this->_eventBase = new $class_name();
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function delay(float $delay, $func, $args)
+    {
+        $class_name = $this->_eventClassName;
+        $event = new $class_name($this->_eventBase, -1, $class_name::TIMEOUT, function () use ($func, $args) {
+            try {
+                $func(...$args);
+            } catch (\Throwable $e) {
+                Worker::stopAll(250, $e);
+            }
+        });
+        if (!$event || !$event->addTimer($delay)) {
+            return false;
+        }
+        $this->_eventTimer[$this->_timerId] = $event;
+        return $this->_timerId++;
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function deleteTimer($timer_id)
+    {
+        if (isset($this->_eventTimer[$timer_id])) {
+            $this->_eventTimer[$timer_id]->del();
+            unset($this->_eventTimer[$timer_id]);
+            return true;
+        }
+        return false;
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function repeat(float $interval, $func, $args)
+    {
+        $class_name = $this->_eventClassName;
+        $event = new $this->_eventClassName($this->_eventBase, -1, $class_name::TIMEOUT | $class_name::PERSIST, function () use ($func, $args) {
+            try {
+                $func(...$args);
+            } catch (\Throwable $e) {
+                Worker::stopAll(250, $e);
+            }
+        });
+        if (!$event || !$event->addTimer($interval)) {
+            return false;
+        }
+        $this->_eventTimer[$this->_timerId] = $event;
+        return $this->_timerId++;
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function onReadable($stream, $func)
+    {
+        $class_name = $this->_eventClassName;
+        $fd_key = (int)$stream;
+        $event = new $this->_eventClassName($this->_eventBase, $stream, $class_name::READ | $class_name::PERSIST, $func, $stream);
+        if (!$event || !$event->add()) {
+            return false;
+        }
+        $this->_writeEvents[$fd_key] = $event;
+        return true;
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function offReadable($stream)
+    {
+        $fd_key = (int)$stream;
+        if (isset($this->_readEvents[$fd_key])) {
+            $this->_readEvents[$fd_key]->del();
+            unset($this->_readEvents[$fd_key]);
+        }
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function onWritable($stream, $func)
+    {
+        $class_name = $this->_eventClassName;
+        $fd_key = (int)$stream;
+        $event = new $this->_eventClassName($this->_eventBase, $stream, $class_name::WRITE | $class_name::PERSIST, $func, $stream);
+        if (!$event || !$event->add()) {
+            return false;
+        }
+        $this->_readEvents[$fd_key] = $event;
+        return true;
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function offWritable($stream)
+    {
+        $fd_key = (int)$stream;
+        if (isset($this->_writeEvents[$fd_key])) {
+            $this->_writeEvents[$fd_key]->del();
+            unset($this->_writeEvents[$fd_key]);
+        }
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function onSignal($signal, $func)
+    {
+        $class_name = $this->_eventClassName;
+        $fd_key = (int)$signal;
+        $event = $class_name::signal($this->_eventBase, $signal, $func);
+        if (!$event || !$event->add()) {
+            return false;
+        }
+        $this->_eventSignal[$fd_key] = $event;
+        return true;
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function offSignal($signal)
+    {
+        $fd_key = (int)$signal;
+        if (isset($this->_eventSignal[$fd_key])) {
+            $this->_eventSignal[$fd_key]->del();
+            unset($this->_eventSignal[$fd_key]);
+        }
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function deleteAllTimer()
+    {
+        foreach ($this->_eventTimer as $event) {
+            $event->del();
+        }
+        $this->_eventTimer = [];
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function run()
+    {
+        $this->_eventBase->loop();
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function stop()
+    {
+        $this->_eventBase->exit();
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function getTimerCount()
+    {
+        return \count($this->_eventTimer);
+    }
+}

+ 111 - 0
src/Events/EventInterface.php

@@ -0,0 +1,111 @@
+<?php
+/**
+ * This file is part of workerman.
+ *
+ * Licensed under The MIT License
+ * For full copyright and license information, please see the MIT-LICENSE.txt
+ * Redistributions of files must retain the above copyright notice.
+ *
+ * @author    walkor<walkor@workerman.net>
+ * @copyright walkor<walkor@workerman.net>
+ * @link      http://www.workerman.net/
+ * @license   http://www.opensource.org/licenses/mit-license.php MIT License
+ */
+namespace Workerman\Events;
+
+interface EventInterface
+{
+    /**
+     * Delay the execution of a callback.
+     * @param float $delay
+     * @param $func
+     * @param $args
+     * @return string
+     */
+    public function delay(float $delay, $func, $args);
+
+    /**
+     * Repeatedly execute a callback.
+     * @param float $interval
+     * @param $func
+     * @param $args
+     * @return string
+     */
+    public function repeat(float $interval, $func, $args);
+
+    /**
+     * Delete a timer.
+     * @param $timer_id
+     * @return mixed
+     */
+    public function deleteTimer($timer_id);
+
+    /**
+     * Execute a callback when a stream resource becomes readable or is closed for reading.
+     * @param $stream
+     * @param $func
+     * @return void
+     */
+    public function onReadable($stream, $func);
+
+    /**
+     * Cancel a callback of stream readable.
+     * @param $stream
+     * @return void
+     */
+    public function offReadable($stream);
+
+    /**
+     * Execute a callback when a stream resource becomes writable or is closed for writing.
+     * @param $stream
+     * @param $func
+     * @return void
+     */
+    public function onWritable($stream, $func);
+
+    /**
+     * Cancel a callback of stream writable.
+     * @param $stream
+     * @return mixed
+     */
+    public function offWritable($stream);
+
+    /**
+     * Execute a callback when a signal is received.
+     * @param $signal
+     * @param $func
+     * @return void
+     */
+    public function onSignal($signal, $func);
+
+    /**
+     * Cancel a callback of signal.
+     * @param $signal
+     * @return void
+     */
+    public function offSignal($signal);
+
+    /**
+     * Delete all timer.
+     * @return void
+     */
+    public function deleteAllTimer();
+
+    /**
+     * Run the event loop.
+     * @return void
+     */
+    public function run();
+
+    /**
+     * Stop event loop.
+     * @return void
+     */
+    public function stop();
+
+    /**
+     * 
+     * @return void
+     */
+    public function getTimerCount();
+}

+ 240 - 0
src/Events/Revolt.php

@@ -0,0 +1,240 @@
+<?php
+/**
+ * This file is part of workerman.
+ *
+ * Licensed under The MIT License
+ * For full copyright and license information, please see the MIT-LICENSE.txt
+ * Redistributions of files must retain the above copyright notice.
+ *
+ * @author    walkor<walkor@workerman.net>
+ * @copyright walkor<walkor@workerman.net>
+ * @link      http://www.workerman.net/
+ * @license   http://www.opensource.org/licenses/mit-license.php MIT License
+ */
+
+namespace Workerman\Events;
+
+use Revolt\EventLoop\Driver;
+use Revolt\EventLoop;
+
+/**
+ * Revolt eventloop
+ */
+class Revolt implements EventInterface
+{
+    /**
+     * @var Driver
+     */
+    protected $_driver = null;
+
+    /**
+     * All listeners for read event.
+     * @var array
+     */
+    protected $_readEvents = [];
+
+    /**
+     * All listeners for write event.
+     * @var array
+     */
+    protected $_writeEvents = [];
+
+    /**
+     * Event listeners of signal.
+     * @var array
+     */
+    protected $_eventSignal = [];
+
+    /**
+     * Event listeners of timer.
+     * @var array
+     */
+    protected $_eventTimer = [];
+
+    /**
+     * Timer id.
+     * @var int
+     */
+    protected $_timerId = 1;
+
+    /**
+     * Construct.
+     */
+    public function __construct()
+    {
+        $this->_driver = EventLoop::getDriver();
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function driver()
+    {
+        return $this->_driver;
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function run()
+    {
+        $this->_driver->run();
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function stop()
+    {
+        foreach ($this->_eventSignal as $cb_id) {
+            $this->_driver->cancel($cb_id);
+        }
+        $this->_driver->stop();
+        pcntl_signal(SIGINT, SIG_IGN);
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function delay(float $delay, $func, $args)
+    {
+        $args = (array)$args;
+        $timer_id = $this->_timerId++;
+        $closure = function () use ($func, $args, $timer_id) {
+            unset($this->_eventTimer[$timer_id]);
+            $func(...$args);
+        };
+        $cb_id = $this->_driver->delay($delay, $closure);
+        $this->_eventTimer[$timer_id] = $cb_id;
+        return $timer_id;
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function repeat(float $interval, $func, $args)
+    {
+        $args = (array)$args;
+        $timer_id = $this->_timerId++;
+        $closure = function () use ($func, $args, $timer_id) {
+            $func(...$args);
+        };
+        $cb_id = $this->_driver->repeat($interval, $closure);
+        $this->_eventTimer[$timer_id] = $cb_id;
+        return $timer_id;
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function onReadable($stream, $func)
+    {
+        $fd_key = (int)$stream;
+        if (isset($this->_readEvents[$fd_key])) {
+            $this->_driver->cancel($this->_readEvents[$fd_key]);
+            unset($this->_readEvents[$fd_key]);
+        }
+
+        $this->_readEvents[$fd_key] = $this->_driver->onReadable($stream, function () use ($stream, $func) {
+            $func($stream);
+        });
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function offReadable($stream)
+    {
+        $fd_key = (int)$stream;
+        if (isset($this->_readEvents[$fd_key])) {
+            $this->_driver->cancel($this->_readEvents[$fd_key]);
+            unset($this->_readEvents[$fd_key]);
+        }
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function onWritable($stream, $func)
+    {
+        $fd_key = (int)$stream;
+        if (isset($this->_writeEvents[$fd_key])) {
+            $this->_driver->cancel($this->_writeEvents[$fd_key]);
+            unset($this->_writeEvents[$fd_key]);
+        }
+        $this->_writeEvents[$fd_key] = $this->_driver->onWritable($stream, function () use ($stream, $func) {
+            $func($stream);
+        });
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function offWritable($stream)
+    {
+        $fd_key = (int)$stream;
+        if (isset($this->_writeEvents[$fd_key])) {
+            $this->_driver->cancel($this->_writeEvents[$fd_key]);
+            unset($this->_writeEvents[$fd_key]);
+        }
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function onSignal($signal, $func)
+    {
+        $fd_key = (int)$signal;
+        if (isset($this->_eventSignal[$fd_key])) {
+            $this->_driver->cancel($this->_eventSignal[$fd_key]);
+            unset($this->_eventSignal[$fd_key]);
+        }
+        $this->_eventSignal[$fd_key] = $this->_driver->onSignal($signal, function () use ($signal, $func) {
+            $func($signal);
+        });
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function offSignal($signal)
+    {
+        $fd_key = (int)$signal;
+        if (isset($this->_eventSignal[$fd_key])) {
+            $this->_driver->cancel($this->_eventSignal[$fd_key]);
+            unset($this->_eventSignal[$fd_key]);
+        }
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function deleteTimer($timer_id)
+    {
+        if (isset($this->_eventTimer[$timer_id])) {
+            $this->_driver->cancel($this->_eventTimer[$timer_id]);
+            unset($this->_eventTimer[$timer_id]);
+            return true;
+        }
+        return false;
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function deleteAllTimer()
+    {
+        foreach ($this->_eventTimer as $cb_id) {
+            $this->_driver->cancel($cb_id);
+        }
+        $this->_eventTimer = [];
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function getTimerCount()
+    {
+        return \count($this->_eventTimer);
+    }
+}

+ 375 - 0
src/Events/Select.php

@@ -0,0 +1,375 @@
+<?php
+/**
+ * This file is part of workerman.
+ *
+ * Licensed under The MIT License
+ * For full copyright and license information, please see the MIT-LICENSE.txt
+ * Redistributions of files must retain the above copyright notice.
+ *
+ * @author    walkor<walkor@workerman.net>
+ * @copyright walkor<walkor@workerman.net>
+ * @link      http://www.workerman.net/
+ * @license   http://www.opensource.org/licenses/mit-license.php MIT License
+ */
+
+namespace Workerman\Events;
+
+/**
+ * select eventloop
+ */
+class Select implements EventInterface
+{
+    /**
+     * All listeners for read/write event.
+     *
+     * @var array
+     */
+    protected $_readEvents = [];
+
+    /**
+     * All listeners for read/write event.
+     *
+     * @var array
+     */
+    protected $_writeEvents = [];
+
+    /**
+     * @var array
+     */
+    protected $_exceptEvents = [];
+
+    /**
+     * Event listeners of signal.
+     *
+     * @var array
+     */
+    protected $_signalEvents = [];
+
+    /**
+     * Fds waiting for read event.
+     *
+     * @var array
+     */
+    protected $_readFds = [];
+
+    /**
+     * Fds waiting for write event.
+     *
+     * @var array
+     */
+    protected $_writeFds = [];
+
+    /**
+     * Fds waiting for except event.
+     *
+     * @var array
+     */
+    protected $_exceptFds = [];
+
+    /**
+     * Timer scheduler.
+     * {['data':timer_id, 'priority':run_timestamp], ..}
+     *
+     * @var \SplPriorityQueue
+     */
+    protected $_scheduler = null;
+
+    /**
+     * All timer event listeners.
+     * [[func, args, flag, timer_interval], ..]
+     *
+     * @var array
+     */
+    protected $_eventTimer = [];
+
+    /**
+     * Timer id.
+     *
+     * @var int
+     */
+    protected $_timerId = 1;
+
+    /**
+     * Select timeout.
+     *
+     * @var int
+     */
+    protected $_selectTimeout = 100000000;
+
+    /**
+     * Construct.
+     */
+    public function __construct()
+    {
+        // Init SplPriorityQueue.
+        $this->_scheduler = new \SplPriorityQueue();
+        $this->_scheduler->setExtractFlags(\SplPriorityQueue::EXTR_BOTH);
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function delay(float $delay, $func, $args)
+    {
+        $timer_id = $this->_timerId++;
+        $run_time = \microtime(true) + $delay;
+        $this->_scheduler->insert($timer_id, -$run_time);
+        $this->_eventTimer[$timer_id] = [$func, (array)$args];
+        $select_timeout = ($run_time - \microtime(true)) * 1000000;
+        $select_timeout = $select_timeout <= 0 ? 1 : (int)$select_timeout;
+        if ($this->_selectTimeout > $select_timeout) {
+            $this->_selectTimeout = $select_timeout;
+        }
+        return $timer_id;
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function repeat(float $delay, $func, $args)
+    {
+        $timer_id = $this->_timerId++;
+        $run_time = \microtime(true) + $delay;
+        $this->_scheduler->insert($timer_id, -$run_time);
+        $this->_eventTimer[$timer_id] = [$func, (array)$args, $delay];
+        $select_timeout = ($run_time - \microtime(true)) * 1000000;
+        if ($this->_selectTimeout > $select_timeout) {
+            $this->_selectTimeout = $select_timeout;
+        }
+        return $timer_id;
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function deleteTimer($timer_id)
+    {
+        if (isset($this->_eventTimer[$timer_id])) {
+            unset($this->_eventTimer[$timer_id]);
+            return true;
+        }
+        return false;
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function onReadable($stream, $func)
+    {
+        $count = \count($this->_readFds);
+        if ($count >= 1024) {
+            echo "Warning: system call select exceeded the maximum number of connections 1024, please install event/libevent extension for more connections.\n";
+        } else if (\DIRECTORY_SEPARATOR !== '/' && $count >= 256) {
+            echo "Warning: system call select exceeded the maximum number of connections 256.\n";
+        }
+        $fd_key = (int)$stream;
+        $this->_readEvents[$fd_key] = $func;
+        $this->_readFds[$fd_key] = $stream;
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function offReadable($stream)
+    {
+        $fd_key = (int)$stream;
+        unset($this->_readEvents[$fd_key], $this->_readFds[$fd_key]);
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function onWritable($stream, $func)
+    {
+        $count = \count($this->_writeFds);
+        if ($count >= 1024) {
+            echo "Warning: system call select exceeded the maximum number of connections 1024, please install event/libevent extension for more connections.\n";
+        } else if (\DIRECTORY_SEPARATOR !== '/' && $count >= 256) {
+            echo "Warning: system call select exceeded the maximum number of connections 256.\n";
+        }
+        $fd_key = (int)$stream;
+        $this->_writeEvents[$fd_key] = $func;
+        $this->_writeFds[$fd_key] = $stream;
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function offWritable($stream)
+    {
+        $fd_key = (int)$stream;
+        unset($this->_writeEvents[$fd_key], $this->_writeFds[$fd_key]);
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function onExcept($stream, $func)
+    {
+        $fd_key = (int)$stream;
+        $this->_exceptEvents[$fd_key] = $func;
+        $this->_exceptFds[$fd_key] = $stream;
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function offExcept($stream)
+    {
+        $fd_key = (int)$stream;
+        unset($this->_exceptEvents[$fd_key], $this->_exceptFds[$fd_key]);
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function onSignal($signal, $func)
+    {
+        if (\DIRECTORY_SEPARATOR !== '/') {
+            return null;
+        }
+        $this->_signalEvents[$signal] = $func;
+        \pcntl_signal($signal, [$this, 'signalHandler']);
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function offsignal($signal)
+    {
+        unset($this->_signalEvents[$signal]);
+        \pcntl_signal($signal, SIG_IGN);
+    }
+
+    /**
+     * Signal handler.
+     *
+     * @param int $signal
+     */
+    public function signalHandler($signal)
+    {
+        $this->_signalEvents[$signal]($signal);
+    }
+
+    /**
+     * Tick for timer.
+     *
+     * @return void
+     */
+    protected function tick()
+    {
+        while (!$this->_scheduler->isEmpty()) {
+            $scheduler_data = $this->_scheduler->top();
+            $timer_id = $scheduler_data['data'];
+            $next_run_time = -$scheduler_data['priority'];
+            $time_now = \microtime(true);
+            $this->_selectTimeout = (int)($next_run_time - $time_now) * 1000000;
+            if ($this->_selectTimeout <= 0) {
+                $this->_scheduler->extract();
+
+                if (!isset($this->_eventTimer[$timer_id])) {
+                    continue;
+                }
+
+                // [func, args, timer_interval]
+                $task_data = $this->_eventTimer[$timer_id];
+                if (isset($task_data[2])) {
+                    $next_run_time = $time_now + $task_data[2];
+                    $this->_scheduler->insert($timer_id, -$next_run_time);
+                } else {
+                    unset($this->_eventTimer[$timer_id]);
+                }
+                $task_data[0]($task_data[1]);
+                continue;
+            }
+            return;
+        }
+        $this->_selectTimeout = 100000000;
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function deleteAllTimer()
+    {
+        $this->_scheduler = new \SplPriorityQueue();
+        $this->_scheduler->setExtractFlags(\SplPriorityQueue::EXTR_BOTH);
+        $this->_eventTimer = [];
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function run()
+    {
+        while (1) {
+            if (\DIRECTORY_SEPARATOR === '/') {
+                // Calls signal handlers for pending signals
+                \pcntl_signal_dispatch();
+            }
+
+            $read = $this->_readFds;
+            $write = $this->_writeFds;
+            $except = $this->_exceptFds;
+
+            if ($read || $write || $except) {
+                // Waiting read/write/signal/timeout events.
+                try {
+                    @stream_select($read, $write, $except, 0, $this->_selectTimeout);
+                } catch (\Throwable $e) {
+                }
+
+            } else {
+                $this->_selectTimeout >= 1 && usleep($this->_selectTimeout);
+                $ret = false;
+            }
+
+            if (!$this->_scheduler->isEmpty()) {
+                $this->tick();
+            }
+
+            foreach ($read as $fd) {
+                $fd_key = (int)$fd;
+                if (isset($this->_readEvents[$fd_key])) {
+                    $this->_readEvents[$fd_key]($fd);
+                }
+            }
+
+            foreach ($write as $fd) {
+                $fd_key = (int)$fd;
+                if (isset($this->_writeEvents[$fd_key])) {
+                    $this->_writeEvents[$fd_key]($fd);
+                }
+            }
+
+            foreach ($except as $fd) {
+                $fd_key = (int)$fd;
+                if (isset($this->_exceptEvents[$fd_key])) {
+                    $this->_exceptEvents[$fd_key]($fd);
+                }
+            }
+        }
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function stop()
+    {
+        $this->deleteAllTimer();
+        foreach ($this->_signalEvents as $signal => $item) {
+            $this->offsignal($signal);
+        }
+        $this->_readFds = $this->_writeFds = $this->_exceptFds = $this->_readEvents
+            = $this->_writeEvents = $this->_exceptEvents = $this->_signalEvents = [];
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function getTimerCount()
+    {
+        return \count($this->_eventTimer);
+    }
+
+}

+ 200 - 0
src/Events/Swoole.php

@@ -0,0 +1,200 @@
+<?php
+/**
+ * This file is part of workerman.
+ *
+ * Licensed under The MIT License
+ * For full copyright and license information, please see the MIT-LICENSE.txt
+ * Redistributions of files must retain the above copyright notice.
+ *
+ * @author    walkor<walkor@workerman.net>
+ * @link      http://www.workerman.net/
+ * @license   http://www.opensource.org/licenses/mit-license.php MIT License
+ */
+
+namespace Workerman\Events;
+
+use Workerman\Worker;
+use Swoole\Event;
+use Swoole\Timer;
+use Swoole\Process;
+
+class Swoole implements EventInterface
+{
+    /**
+     * All listeners for read timer
+     * @var array
+     */
+    protected $_eventTimer = [];
+
+    /**
+     * All listeners for read event.
+     * @var array
+     */
+    protected $_readEvents = [];
+
+    /**
+     * All listeners for write event.
+     * @var array
+     */
+    protected $_writeEvents = [];
+
+    /**
+     * {@inheritdoc}
+     */
+    public function delay(float $delay, $func, $args)
+    {
+        $t = (int)($delay * 1000);
+        $t = $t < 1 ? 1 : $t;
+        $timer_id = Timer::after($t, function () use ($func, $args, &$timer_id) {
+            unset($this->_eventTimer[$timer_id]);
+            try {
+                $func(...(array)$args);
+            } catch (\Throwable $e) {
+                Worker::stopAll(250, $e);
+            }
+        });
+        $this->_eventTimer[$timer_id] = $timer_id;
+        return $timer_id;
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function deleteTimer($timer_id)
+    {
+        if (isset($this->_eventTimer[$timer_id])) {
+            $res = Timer::clear($timer_id);
+            unset($this->_eventTimer[$timer_id]);
+            return $res;
+        }
+        return false;
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function repeat(float $interval, $func, $args)
+    {
+        if ($this->mapId > \PHP_INT_MAX) {
+            $this->mapId = 0;
+        }
+        $t = (int)($interval * 1000);
+        $t = $t < 1 ? 1 : $t;
+        $timer_id = Timer::tick($t, function () use ($func, $args) {
+            try {
+                $func(...(array)$args);
+            } catch (\Throwable $e) {
+                Worker::stopAll(250, $e);
+            }
+        });
+        $this->_eventTimer[$timer_id] = $timer_id;
+        return $timer_id;
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function onReadable($stream, $func)
+    {
+        $this->_readEvents[(int)$stream] = $stream;
+        return Event::add($stream, $func, null, \SWOOLE_EVENT_READ);
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function offReadable($stream)
+    {
+        $fd = (int)$stream;
+        if (!isset($this->_readEvents[$fd])) {
+            return;
+        }
+        unset($this->_readEvents[$fd]);
+        if (!isset($this->_writeEvents[$fd])) {
+            return Event::del($stream);
+        }
+        return Event::set($stream, null, null, \SWOOLE_EVENT_READ);
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function onWritable($stream, $func)
+    {
+        $this->_writeEvents[(int)$stream] = $stream;
+        return Event::add($stream, null, $func, \SWOOLE_EVENT_WRITE);
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function offWritable($stream)
+    {
+        $fd = (int)$stream;
+        if (!isset($this->_writeEvents[$fd])) {
+            return;
+        }
+        unset($this->_writeEvents[$fd]);
+        if (!isset($this->_readEvents[$fd])) {
+            return Event::del($stream);
+        }
+        return Event::set($stream, null, null, \SWOOLE_EVENT_WRITE);
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function onSignal($signal, $func)
+    {
+        return Process::signal($signal, $func);
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function offSignal($signal)
+    {
+        return Process::signal($signal, function () {
+        });
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function deleteAllTimer()
+    {
+        foreach ($this->_eventTimer as $timer_id) {
+            Timer::clear($timer_id);
+        }
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function run()
+    {
+        Event::wait();
+    }
+
+    /**
+     * Destroy loop.
+     *
+     * @return void
+     */
+    public function stop()
+    {
+        Event::exit();
+        \posix_kill(posix_getpid(), SIGINT);
+    }
+
+    /**
+     * Get timer count.
+     *
+     * @return integer
+     */
+    public function getTimerCount()
+    {
+        return \count($this->_eventTimer);
+    }
+
+}

+ 2 - 1
Protocols/Frame.php → src/Protocols/Frame.php

@@ -11,6 +11,7 @@
  * @link      http://www.workerman.net/
  * @license   http://www.opensource.org/licenses/mit-license.php MIT License
  */
+
 namespace Workerman\Protocols;
 
 use Workerman\Connection\TcpConnection;
@@ -23,7 +24,7 @@ class Frame
     /**
      * Check the integrity of the package.
      *
-     * @param string        $buffer
+     * @param string $buffer
      * @param TcpConnection $connection
      * @return int
      */

+ 13 - 14
Protocols/Http.php → src/Protocols/Http.php

@@ -11,13 +11,12 @@
  * @link      http://www.workerman.net/
  * @license   http://www.opensource.org/licenses/mit-license.php MIT License
  */
+
 namespace Workerman\Protocols;
 
 use Workerman\Connection\TcpConnection;
 use Workerman\Protocols\Http\Request;
 use Workerman\Protocols\Http\Response;
-use Workerman\Protocols\Websocket;
-use Workerman\Worker;
 
 /**
  * Class Http.
@@ -30,7 +29,7 @@ class Http
      *
      * @var string
      */
-    protected static $_requestClass = 'Workerman\Protocols\Http\Request';
+    protected static $_requestClass = Request::class;
 
     /**
      * Session name.
@@ -47,7 +46,7 @@ class Http
     protected static $_uploadTmpDir = '';
 
     /**
-     * Open cache.
+     * Cache.
      *
      * @var bool.
      */
@@ -100,7 +99,7 @@ class Http
      */
     public static function input($recv_buffer, TcpConnection $connection)
     {
-        static $input = array();
+        static $input = [];
         if (!isset($recv_buffer[512]) && isset($input[$recv_buffer])) {
             return $input[$recv_buffer];
         }
@@ -121,7 +120,7 @@ class Http
             if (!isset($recv_buffer[512])) {
                 $input[$recv_buffer] = $head_len;
                 if (\count($input) > 512) {
-                    unset($input[key($input)]);
+                    unset($input[\key($input)]);
                 }
             }
             return $head_len;
@@ -142,7 +141,7 @@ class Http
             if (!isset($recv_buffer[512])) {
                 $input[$recv_buffer] = $length;
                 if (\count($input) > 512) {
-                    unset($input[key($input)]);
+                    unset($input[\key($input)]);
                 }
             }
             if ($length > $connection->maxPackageSize) {
@@ -165,13 +164,13 @@ class Http
      */
     public static function decode($recv_buffer, TcpConnection $connection)
     {
-        static $requests = array();
+        static $requests = [];
         $cacheable = static::$_enableCache && !isset($recv_buffer[512]);
         if (true === $cacheable && isset($requests[$recv_buffer])) {
-            $request = $requests[$recv_buffer];
+            $request = clone $requests[$recv_buffer];
             $request->connection = $connection;
             $connection->__request = $request;
-            $request->properties = array();
+            $request->properties = [];
             return $request;
         }
         $request = new static::$_requestClass($recv_buffer);
@@ -180,7 +179,7 @@ class Http
         if (true === $cacheable) {
             $requests[$recv_buffer] = $request;
             if (\count($requests) > 512) {
-                unset($requests[key($requests)]);
+                unset($requests[\key($requests)]);
             }
         }
         return $request;
@@ -229,10 +228,10 @@ class Http
             $length = $response->file['length'];
             $file_size = (int)\filesize($file);
             $body_len = $length > 0 ? $length : $file_size - $offset;
-            $response->withHeaders(array(
+            $response->withHeaders([
                 'Content-Length' => $body_len,
-                'Accept-Ranges'  => 'bytes',
-            ));
+                'Accept-Ranges' => 'bytes',
+            ]);
             if ($offset || $length) {
                 $offset_end = $offset + $body_len - 1;
                 $response->header('Content-Range', "bytes $offset-$offset_end/$file_size");

+ 2 - 1
Protocols/Http/Chunk.php → src/Protocols/Http/Chunk.php

@@ -11,6 +11,7 @@
  * @link      http://www.workerman.net/
  * @license   http://www.opensource.org/licenses/mit-license.php MIT License
  */
+
 namespace Workerman\Protocols\Http;
 
 
@@ -43,6 +44,6 @@ class Chunk
      */
     public function __toString()
     {
-        return \dechex(\strlen($this->_buffer))."\r\n$this->_buffer\r\n";
+        return \dechex(\strlen($this->_buffer)) . "\r\n$this->_buffer\r\n";
     }
 }

+ 74 - 39
Protocols/Http/Request.php → src/Protocols/Http/Request.php

@@ -11,6 +11,7 @@
  * @link      http://www.workerman.net/
  * @license   http://www.opensource.org/licenses/mit-license.php MIT License
  */
+
 namespace Workerman\Protocols\Http;
 
 use Workerman\Connection\TcpConnection;
@@ -43,7 +44,7 @@ class Request
      *
      * @var array
      */
-    public $properties = array();
+    public $properties = [];
 
     /**
      * Http buffer.
@@ -64,21 +65,21 @@ class Request
      *
      * @var array
      */
-    protected static $_headerCache = array();
+    protected static $_headerCache = [];
 
     /**
      * Get cache.
      *
      * @var array
      */
-    protected static $_getCache = array();
+    protected static $_getCache = [];
 
     /**
      * Post cache.
      *
      * @var array
      */
-    protected static $_postCache = array();
+    protected static $_postCache = [];
 
     /**
      * Enable cache.
@@ -163,7 +164,7 @@ class Request
     public function cookie($name = null, $default = null)
     {
         if (!isset($this->_data['cookie'])) {
-            $this->_data['cookie'] = array();
+            $this->_data['cookie'] = [];
             \parse_str(\preg_replace('/; ?/', '&', $this->header('cookie', '')), $this->_data['cookie']);
         }
         if ($name === null) {
@@ -291,8 +292,11 @@ class Request
      *
      * @return bool|mixed
      */
-    public function sessionId()
+    public function sessionId($session_id = null)
     {
+        if ($session_id !== null) {
+            $this->sid = $session_id;
+        }
         if (!isset($this->sid)) {
             $session_name = Http::sessionName();
             $sid = $this->cookie($session_name);
@@ -303,13 +307,7 @@ class Request
                 }
                 $sid = static::createSessionId();
                 $cookie_params = \session_get_cookie_params();
-                $this->connection->__header['Set-Cookie'] = array($session_name . '=' . $sid
-                    . (empty($cookie_params['domain']) ? '' : '; Domain=' . $cookie_params['domain'])
-                    . (empty($cookie_params['lifetime']) ? '' : '; Max-Age=' . $cookie_params['lifetime'])
-                    . (empty($cookie_params['path']) ? '' : '; Path=' . $cookie_params['path'])
-                    . (empty($cookie_params['samesite']) ? '' : '; SameSite=' . $cookie_params['samesite'])
-                    . (!$cookie_params['secure'] ? '' : '; Secure')
-                    . (!$cookie_params['httponly'] ? '' : '; HttpOnly'));
+                $this->setSidCookie($session_name, $sid, $cookie_params);
             }
             $this->sid = $sid;
         }
@@ -317,6 +315,26 @@ class Request
     }
 
     /**
+     * Session regenerate id
+     * @param bool $delete_old_session
+     * @return void
+     */
+    public function sessionRegenerateId($delete_old_session = false)
+    {
+        $session = $this->session();
+        $session_data = $session->all();
+        if ($delete_old_session) {
+            $session->flush();
+        }
+        $new_sid = static::createSessionId();
+        $session = new Session($new_sid);
+        $session->put($session_data);
+        $cookie_params = \session_get_cookie_params();
+        $session_name = Http::sessionName();
+        $this->setSidCookie($session_name, $new_sid, $cookie_params);
+    }
+
+    /**
      * Get http raw head.
      *
      * @return string
@@ -391,7 +409,7 @@ class Request
      */
     protected function parseHeaders()
     {
-        $this->_data['headers'] = array();
+        $this->_data['headers'] = [];
         $raw_head = $this->rawHead();
         $end_line_position = \strpos($raw_head, "\r\n");
         if ($end_line_position === false) {
@@ -435,7 +453,7 @@ class Request
     protected function parseGet()
     {
         $query_string = $this->queryString();
-        $this->_data['get'] = array();
+        $this->_data['get'] = [];
         if ($query_string === '') {
             return;
         }
@@ -461,7 +479,7 @@ class Request
     protected function parsePost()
     {
         $body_buffer = $this->rawBody();
-        $this->_data['post'] = $this->_data['files'] = array();
+        $this->_data['post'] = $this->_data['files'] = [];
         if ($body_buffer === '') {
             return;
         }
@@ -477,7 +495,7 @@ class Request
             return;
         }
         if (\preg_match('/\bjson\b/i', $content_type)) {
-            $this->_data['post'] = (array) json_decode($body_buffer, true);
+            $this->_data['post'] = (array)\json_decode($body_buffer, true);
         } else {
             \parse_str($body_buffer, $this->_data['post']);
         }
@@ -497,15 +515,15 @@ class Request
      */
     protected function parseUploadFiles($http_post_boundary)
     {
-        $http_post_boundary  = \trim($http_post_boundary, '"');
-        $http_body           = $this->rawBody();
-        $http_body           = \substr($http_body, 0, \strlen($http_body) - (\strlen($http_post_boundary) + 4));
+        $http_post_boundary = \trim($http_post_boundary, '"');
+        $http_body = $this->rawBody();
+        $http_body = \substr($http_body, 0, \strlen($http_body) - (\strlen($http_post_boundary) + 4));
         $boundary_data_array = \explode($http_post_boundary . "\r\n", $http_body);
         if ($boundary_data_array[0] === '' || $boundary_data_array[0] === "\r\n") {
             unset($boundary_data_array[0]);
         }
-        $key   = -1;
-        $files = array();
+        $key = -1;
+        $files = [];
         $post_str = '';
         foreach ($boundary_data_array as $boundary_data_buffer) {
             list($boundary_header_buffer, $boundary_value) = \explode("\r\n\r\n", $boundary_data_buffer, 2);
@@ -519,9 +537,9 @@ class Request
                     case "content-disposition":
                         // Is file data.
                         if (\preg_match('/name="(.*?)"; filename="(.*?)"/i', $header_value, $match)) {
-                            $error          = 0;
-                            $tmp_file       = '';
-                            $size           = \strlen($boundary_value);
+                            $error = 0;
+                            $tmp_file = '';
+                            $size = \strlen($boundary_value);
                             $tmp_upload_dir = HTTP::uploadTmpDir();
                             if (!$tmp_upload_dir) {
                                 $error = UPLOAD_ERR_NO_TMP_DIR;
@@ -534,31 +552,31 @@ class Request
                                 }
                             }
                             if (!isset($files[$key])) {
-                                $files[$key] = array();
+                                $files[$key] = [];
                             }
                             // Parse upload files.
-                            $files[$key] += array(
-                                'key'      => $match[1],
-                                'name'     => $match[2],
+                            $files[$key] += [
+                                'key' => $match[1],
+                                'name' => $match[2],
                                 'tmp_name' => $tmp_file,
-                                'size'     => $size,
-                                'error'    => $error,
-                                'type'     => null,
-                            );
+                                'size' => $size,
+                                'error' => $error,
+                                'type' => null,
+                            ];
                             break;
                         } // Is post field.
                         else {
                             // Parse $_POST.
                             if (\preg_match('/name="(.*?)"$/', $header_value, $match)) {
                                 $key = $match[1];
-                                $post_str .= \urlencode($key)."=".\urlencode($boundary_value).'&';
+                                $post_str .= \urlencode($key) . "=" . \urlencode($boundary_value) . '&';
                             }
                         }
                         break;
                     case "content-type":
                         // add file_type
                         if (!isset($files[$key])) {
-                            $files[$key] = array();
+                            $files[$key] = [];
                         }
                         $files[$key]['type'] = \trim($header_value);
                         break;
@@ -568,10 +586,10 @@ class Request
         foreach ($files as $file) {
             $key = $file['key'];
             unset($file['key']);
-            $str = \urlencode($key)."=1";
+            $str = \urlencode($key) . "=1";
             $result = [];
             \parse_str($str, $result);
-            \array_walk_recursive($result, function(&$value) use ($file) {
+            \array_walk_recursive($result, function (&$value) use ($file) {
                 $value = $file;
             });
             $this->_data['files'] = \array_merge($this->_data['files'], $result);
@@ -586,7 +604,7 @@ class Request
      *
      * @return string
      */
-    protected static function createSessionId()
+    public static function createSessionId()
     {
         return \bin2hex(\pack('d', \microtime(true)) . \pack('N', \mt_rand()));
     }
@@ -653,7 +671,7 @@ class Request
     {
         if (isset($this->_data['files'])) {
             \clearstatcache();
-            \array_walk_recursive($this->_data['files'], function($value, $key){
+            \array_walk_recursive($this->_data['files'], function ($value, $key) {
                 if ($key === 'tmp_name') {
                     if (\is_file($value)) {
                         \unlink($value);
@@ -662,4 +680,21 @@ class Request
             });
         }
     }
+
+    /**
+     * @param string $session_name
+     * @param string $sid
+     * @param array $cookie_params
+     * @return void
+     */
+    protected function setSidCookie(string $session_name, string $sid, array $cookie_params)
+    {
+        $this->connection->__header['Set-Cookie'] = [$session_name . '=' . $sid
+            . (empty($cookie_params['domain']) ? '' : '; Domain=' . $cookie_params['domain'])
+            . (empty($cookie_params['lifetime']) ? '' : '; Max-Age=' . $cookie_params['lifetime'])
+            . (empty($cookie_params['path']) ? '' : '; Path=' . $cookie_params['path'])
+            . (empty($cookie_params['samesite']) ? '' : '; SameSite=' . $cookie_params['samesite'])
+            . (!$cookie_params['secure'] ? '' : '; Secure')
+            . (!$cookie_params['httponly'] ? '' : '; HttpOnly')];
+    }
 }

+ 44 - 27
Protocols/Http/Response.php → src/Protocols/Http/Response.php

@@ -11,6 +11,7 @@
  * @link      http://www.workerman.net/
  * @license   http://www.opensource.org/licenses/mit-license.php MIT License
  */
+
 namespace Workerman\Protocols\Http;
 
 /**
@@ -72,7 +73,7 @@ class Response
      *
      * @var array
      */
-    protected static $_phrases = array(
+    protected static $_phrases = [
         100 => 'Continue',
         101 => 'Switching Protocols',
         102 => 'Processing',
@@ -131,14 +132,15 @@ class Response
         507 => 'Insufficient Storage',
         508 => 'Loop Detected',
         511 => 'Network Authentication Required',
-    );
+    ];
 
     /**
      * Init.
      *
      * @return void
      */
-    public static function init() {
+    public static function init()
+    {
         static::initMimeTypeMap();
     }
 
@@ -151,9 +153,10 @@ class Response
      */
     public function __construct(
         $status = 200,
-        $headers = array(),
+        $headers = [],
         $body = ''
-    ) {
+    )
+    {
         $this->_status = $status;
         $this->_header = $headers;
         $this->_body = (string)$body;
@@ -166,7 +169,8 @@ class Response
      * @param string $value
      * @return $this
      */
-    public function header($name, $value) {
+    public function header($name, $value)
+    {
         $this->_header[$name] = $value;
         return $this;
     }
@@ -178,7 +182,8 @@ class Response
      * @param string $value
      * @return Response
      */
-    public function withHeader($name, $value) {
+    public function withHeader($name, $value)
+    {
         return $this->header($name, $value);
     }
 
@@ -188,18 +193,20 @@ class Response
      * @param array $headers
      * @return $this
      */
-    public function withHeaders($headers) {
+    public function withHeaders($headers)
+    {
         $this->_header = \array_merge_recursive($this->_header, $headers);
         return $this;
     }
-    
+
     /**
      * Remove header.
      *
      * @param string $name
      * @return $this
      */
-    public function withoutHeader($name) {
+    public function withoutHeader($name)
+    {
         unset($this->_header[$name]);
         return $this;
     }
@@ -210,7 +217,8 @@ class Response
      * @param string $name
      * @return null|array|string
      */
-    public function getHeader($name) {
+    public function getHeader($name)
+    {
         if (!isset($this->_header[$name])) {
             return null;
         }
@@ -222,7 +230,8 @@ class Response
      *
      * @return array
      */
-    public function getHeaders() {
+    public function getHeaders()
+    {
         return $this->_header;
     }
 
@@ -233,7 +242,8 @@ class Response
      * @param string|null $reason_phrase
      * @return $this
      */
-    public function withStatus($code, $reason_phrase = null) {
+    public function withStatus($code, $reason_phrase = null)
+    {
         $this->_status = $code;
         $this->_reason = $reason_phrase;
         return $this;
@@ -244,7 +254,8 @@ class Response
      *
      * @return int
      */
-    public function getStatusCode() {
+    public function getStatusCode()
+    {
         return $this->_status;
     }
 
@@ -253,7 +264,8 @@ class Response
      *
      * @return string
      */
-    public function getReasonPhrase() {
+    public function getReasonPhrase()
+    {
         return $this->_reason;
     }
 
@@ -263,7 +275,8 @@ class Response
      * @param int $version
      * @return $this
      */
-    public function withProtocolVersion($version) {
+    public function withProtocolVersion($version)
+    {
         $this->_version = $version;
         return $this;
     }
@@ -274,17 +287,19 @@ class Response
      * @param string $body
      * @return $this
      */
-    public function withBody($body) {
+    public function withBody($body)
+    {
         $this->_body = $body;
         return $this;
     }
 
     /**
      * Get http raw body.
-     * 
+     *
      * @return string
      */
-    public function rawBody() {
+    public function rawBody()
+    {
         return $this->_body;
     }
 
@@ -296,11 +311,12 @@ class Response
      * @param int $length
      * @return $this
      */
-    public function withFile($file, $offset = 0, $length = 0) {
+    public function withFile($file, $offset = 0, $length = 0)
+    {
         if (!\is_file($file)) {
             return $this->withStatus(404)->withBody('<h3>404 Not Found</h3>');
         }
-        $this->file = array('file' => $file, 'offset' => $offset, 'length' => $length);
+        $this->file = ['file' => $file, 'offset' => $offset, 'length' => $length];
         return $this;
     }
 
@@ -317,7 +333,7 @@ class Response
      * @param bool $same_site
      * @return $this
      */
-    public function cookie($name, $value = '', $max_age = 0, $path = '', $domain = '', $secure = false, $http_only = false, $same_site  = false)
+    public function cookie($name, $value = '', $max_age = 0, $path = '', $domain = '', $secure = false, $http_only = false, $same_site = false)
     {
         $this->_header['Set-Cookie'][] = $name . '=' . \rawurlencode($value)
             . (empty($domain) ? '' : '; Domain=' . $domain)
@@ -325,7 +341,7 @@ class Response
             . (empty($path) ? '' : '; Path=' . $path)
             . (!$secure ? '' : '; Secure')
             . (!$http_only ? '' : '; HttpOnly')
-            . (empty($same_site ) ? '' : '; SameSite=' . $same_site);
+            . (empty($same_site) ? '' : '; SameSite=' . $same_site);
         return $this;
     }
 
@@ -375,7 +391,7 @@ class Response
 
         if (!isset($headers['Last-Modified'])) {
             if ($mtime = \filemtime($file)) {
-                $head .= 'Last-Modified: '. \gmdate('D, d M Y H:i:s', $mtime) . ' GMT' . "\r\n";
+                $head .= 'Last-Modified: ' . \gmdate('D, d M Y H:i:s', $mtime) . ' GMT' . "\r\n";
             }
         }
 
@@ -427,7 +443,7 @@ class Response
         if (!isset($headers['Transfer-Encoding'])) {
             $head .= "Content-Length: $body_len\r\n\r\n";
         } else {
-            return "$head\r\n".dechex($body_len)."\r\n{$this->_body}\r\n";
+            return "$head\r\n" . dechex($body_len) . "\r\n{$this->_body}\r\n";
         }
 
         // The whole http package
@@ -445,8 +461,8 @@ class Response
         $items = \file($mime_file, \FILE_IGNORE_NEW_LINES | \FILE_SKIP_EMPTY_LINES);
         foreach ($items as $content) {
             if (\preg_match("/\s*(\S+)\s+(\S.+)/", $content, $match)) {
-                $mime_type       = $match[1];
-                $extension_var   = $match[2];
+                $mime_type = $match[1];
+                $extension_var = $match[2];
                 $extension_array = \explode(' ', \substr($extension_var, 0, -1));
                 foreach ($extension_array as $file_extension) {
                     static::$_mimeTypeMap[$file_extension] = $mime_type;
@@ -455,4 +471,5 @@ class Response
         }
     }
 }
+
 Response::init();

+ 1 - 0
Protocols/Http/ServerSentEvents.php → src/Protocols/Http/ServerSentEvents.php

@@ -11,6 +11,7 @@
  * @link      http://www.workerman.net/
  * @license   http://www.opensource.org/licenses/mit-license.php MIT License
  */
+
 namespace Workerman\Protocols\Http;
 
 /**

+ 5 - 4
Protocols/Http/Session.php → src/Protocols/Http/Session.php

@@ -11,6 +11,7 @@
  * @link      http://www.workerman.net/
  * @license   http://www.opensource.org/licenses/mit-license.php MIT License
  */
+
 namespace Workerman\Protocols\Http;
 
 use Workerman\Protocols\Http\Session\SessionHandlerInterface;
@@ -68,7 +69,7 @@ class Session
      *
      * @var array
      */
-    protected $_data = array();
+    protected $_data = [];
 
     /**
      * Session changed and need to save.
@@ -163,7 +164,7 @@ class Session
     /**
      * Store data in the session.
      *
-     * @param string $key
+     * @param string|array $key
      * @param mixed|null $value
      */
     public function put($key, $value = null)
@@ -216,7 +217,7 @@ class Session
     public function flush()
     {
         $this->_needSave = true;
-        $this->_data = array();
+        $this->_data = [];
     }
 
     /**
@@ -260,7 +261,7 @@ class Session
 
     /**
      * Refresh session expire time.
-     * 
+     *
      * @return bool
      */
     public function refresh()

+ 18 - 12
Protocols/Http/Session/FileSessionHandler.php → src/Protocols/Http/Session/FileSessionHandler.php

@@ -11,6 +11,7 @@
  * @link      http://www.workerman.net/
  * @license   http://www.opensource.org/licenses/mit-license.php MIT License
  */
+
 namespace Workerman\Protocols\Http\Session;
 
 /**
@@ -36,7 +37,8 @@ class FileSessionHandler implements SessionHandlerInterface
     /**
      * Init.
      */
-    public static function init() {
+    public static function init()
+    {
         $save_path = @\session_save_path();
         if (!$save_path || \strpos($save_path, 'tcp://') === 0) {
             $save_path = \sys_get_temp_dir();
@@ -48,7 +50,8 @@ class FileSessionHandler implements SessionHandlerInterface
      * FileSessionHandler constructor.
      * @param array $config
      */
-    public function __construct($config = array()) {
+    public function __construct($config = [])
+    {
         if (isset($config['save_path'])) {
             static::sessionSavePath($config['save_path']);
         }
@@ -81,7 +84,7 @@ class FileSessionHandler implements SessionHandlerInterface
      */
     public function write($session_id, $session_data)
     {
-        $temp_file = static::$_sessionSavePath.uniqid(mt_rand(), true);
+        $temp_file = static::$_sessionSavePath . uniqid(mt_rand(), true);
         if (!\file_put_contents($temp_file, $session_data)) {
             return false;
         }
@@ -90,13 +93,13 @@ class FileSessionHandler implements SessionHandlerInterface
 
     /**
      * Update sesstion modify time.
-     * 
+     *
      * @see https://www.php.net/manual/en/class.sessionupdatetimestamphandlerinterface.php
      * @see https://www.php.net/manual/zh/function.touch.php
-     * 
+     *
      * @param string $id Session id.
      * @param string $data Session Data.
-     * 
+     *
      * @return bool
      */
     public function updateTimestamp($id, $data = "")
@@ -135,10 +138,11 @@ class FileSessionHandler implements SessionHandlerInterface
     /**
      * {@inheritdoc}
      */
-    public function gc($maxlifetime) {
+    public function gc($maxlifetime)
+    {
         $time_now = \time();
         foreach (\glob(static::$_sessionSavePath . static::$_sessionFilePrefix . '*') as $file) {
-            if(\is_file($file) && $time_now - \filemtime($file) > $maxlifetime) {
+            if (\is_file($file) && $time_now - \filemtime($file) > $maxlifetime) {
                 \unlink($file);
             }
         }
@@ -150,8 +154,9 @@ class FileSessionHandler implements SessionHandlerInterface
      * @param string $session_id
      * @return string
      */
-    protected static function sessionFile($session_id) {
-        return static::$_sessionSavePath.static::$_sessionFilePrefix.$session_id;
+    protected static function sessionFile($session_id)
+    {
+        return static::$_sessionSavePath . static::$_sessionFilePrefix . $session_id;
     }
 
     /**
@@ -160,9 +165,10 @@ class FileSessionHandler implements SessionHandlerInterface
      * @param string $path
      * @return string
      */
-    public static function sessionSavePath($path) {
+    public static function sessionSavePath($path)
+    {
         if ($path) {
-            if ($path[\strlen($path)-1] !== DIRECTORY_SEPARATOR) {
+            if ($path[\strlen($path) - 1] !== DIRECTORY_SEPARATOR) {
                 $path .= DIRECTORY_SEPARATOR;
             }
             static::$_sessionSavePath = $path;

+ 1 - 0
Protocols/Http/Session/RedisSessionHandler.php → src/Protocols/Http/Session/RedisSessionHandler.php

@@ -11,6 +11,7 @@
  * @link      http://www.workerman.net/
  * @license   http://www.opensource.org/licenses/mit-license.php MIT License
  */
+
 namespace Workerman\Protocols\Http\Session;
 
 /**

+ 4 - 3
Protocols/Http/Session/SessionHandlerInterface.php → src/Protocols/Http/Session/SessionHandlerInterface.php

@@ -11,6 +11,7 @@
  * @link      http://www.workerman.net/
  * @license   http://www.opensource.org/licenses/mit-license.php MIT License
  */
+
 namespace Workerman\Protocols\Http\Session;
 
 interface SessionHandlerInterface
@@ -101,12 +102,12 @@ interface SessionHandlerInterface
 
     /**
      * Update sesstion modify time.
-     * 
+     *
      * @see https://www.php.net/manual/en/class.sessionupdatetimestamphandlerinterface.php
-     * 
+     *
      * @param string $id Session id.
      * @param string $data Session Data.
-     * 
+     *
      * @return bool
      */
     public function updateTimestamp($id, $data = "");

+ 0 - 0
Protocols/Http/mime.types → src/Protocols/Http/mime.types


+ 5 - 4
Protocols/ProtocolInterface.php → src/Protocols/ProtocolInterface.php

@@ -11,6 +11,7 @@
  * @link      http://www.workerman.net/
  * @license   http://www.opensource.org/licenses/mit-license.php MIT License
  */
+
 namespace Workerman\Protocols;
 
 use Workerman\Connection\ConnectionInterface;
@@ -26,7 +27,7 @@ interface ProtocolInterface
      * If length is unknow please return 0 that mean wating more data.
      * If the package has something wrong please return false the connection will be closed.
      *
-     * @param string              $recv_buffer
+     * @param string $recv_buffer
      * @param ConnectionInterface $connection
      * @return int|false
      */
@@ -35,7 +36,7 @@ interface ProtocolInterface
     /**
      * Decode package and emit onMessage($message) callback, $message is the result that decode returned.
      *
-     * @param string              $recv_buffer
+     * @param string $recv_buffer
      * @param ConnectionInterface $connection
      * @return mixed
      */
@@ -43,8 +44,8 @@ interface ProtocolInterface
 
     /**
      * Encode package brefore sending to client.
-     * 
-     * @param mixed               $data
+     *
+     * @param mixed $data
      * @param ConnectionInterface $connection
      * @return string
      */

+ 2 - 1
Protocols/Text.php → src/Protocols/Text.php

@@ -11,6 +11,7 @@
  * @link      http://www.workerman.net/
  * @license   http://www.opensource.org/licenses/mit-license.php MIT License
  */
+
 namespace Workerman\Protocols;
 
 use Workerman\Connection\ConnectionInterface;
@@ -23,7 +24,7 @@ class Text
     /**
      * Check the integrity of the package.
      *
-     * @param string        $buffer
+     * @param string $buffer
      * @param ConnectionInterface $connection
      * @return int
      */

+ 46 - 114
Protocols/Websocket.php → src/Protocols/Websocket.php

@@ -11,10 +11,12 @@
  * @link      http://www.workerman.net/
  * @license   http://www.opensource.org/licenses/mit-license.php MIT License
  */
+
 namespace Workerman\Protocols;
 
 use Workerman\Connection\ConnectionInterface;
 use Workerman\Connection\TcpConnection;
+use Workerman\Protocols\Http\Request;
 use Workerman\Worker;
 
 /**
@@ -39,7 +41,7 @@ class Websocket implements \Workerman\Protocols\ProtocolInterface
     /**
      * Check the integrity of the package.
      *
-     * @param string              $buffer
+     * @param string $buffer
      * @param ConnectionInterface $connection
      * @return int
      */
@@ -65,11 +67,11 @@ class Websocket implements \Workerman\Protocols\ProtocolInterface
                 return 0;
             }
         } else {
-            $firstbyte    = \ord($buffer[0]);
-            $secondbyte   = \ord($buffer[1]);
-            $data_len     = $secondbyte & 127;
+            $firstbyte = \ord($buffer[0]);
+            $secondbyte = \ord($buffer[1]);
+            $data_len = $secondbyte & 127;
             $is_fin_frame = $firstbyte >> 7;
-            $masked       = $secondbyte >> 7;
+            $masked = $secondbyte >> 7;
 
             if (!$masked) {
                 Worker::safeEcho("frame not masked so close the connection\n");
@@ -77,7 +79,7 @@ class Websocket implements \Workerman\Protocols\ProtocolInterface
                 return 0;
             }
 
-            $opcode       = $firstbyte & 0xf;
+            $opcode = $firstbyte & 0xf;
             switch ($opcode) {
                 case 0x0:
                     break;
@@ -90,12 +92,11 @@ class Websocket implements \Workerman\Protocols\ProtocolInterface
                 // Close package.
                 case 0x8:
                     // Try to emit onWebSocketClose callback.
-                    if (isset($connection->onWebSocketClose) || isset($connection->worker->onWebSocketClose)) {
+                    $close_cb = $connection->onWebSocketClose ?? $connection->worker->onWebSocketClose ?? false;
+                    if ($close_cb) {
                         try {
-                            \call_user_func(isset($connection->onWebSocketClose)?$connection->onWebSocketClose:$connection->worker->onWebSocketClose, $connection);
-                        } catch (\Exception $e) {
-                            Worker::stopAll(250, $e);
-                        } catch (\Error $e) {
+                            $close_cb($connection);
+                        } catch (\Throwable $e) {
                             Worker::stopAll(250, $e);
                         }
                     } // Close connection.
@@ -123,7 +124,7 @@ class Websocket implements \Workerman\Protocols\ProtocolInterface
                 if ($head_len > $recv_len) {
                     return 0;
                 }
-                $pack     = \unpack('nn/ntotal_len', $buffer);
+                $pack = \unpack('nn/ntotal_len', $buffer);
                 $data_len = $pack['total_len'];
             } else {
                 if ($data_len === 127) {
@@ -131,8 +132,8 @@ class Websocket implements \Workerman\Protocols\ProtocolInterface
                     if ($head_len > $recv_len) {
                         return 0;
                     }
-                    $arr      = \unpack('n/N2c', $buffer);
-                    $data_len = $arr['c1']*4294967296 + $arr['c2'];
+                    $arr = \unpack('n/N2c', $buffer);
+                    $data_len = $arr['c1'] * 4294967296 + $arr['c2'];
                 }
             }
             $current_frame_length = $head_len + $data_len;
@@ -151,12 +152,11 @@ class Websocket implements \Workerman\Protocols\ProtocolInterface
                         $connection->consumeRecvBuffer($current_frame_length);
                         $tmp_connection_type = isset($connection->websocketType) ? $connection->websocketType : static::BINARY_TYPE_BLOB;
                         $connection->websocketType = "\x8a";
-                        if (isset($connection->onWebSocketPing) || isset($connection->worker->onWebSocketPing)) {
+                        $ping_cb = $connection->onWebSocketPing ?? $connection->worker->onWebSocketPing ?? false;
+                        if ($ping_cb) {
                             try {
-                                \call_user_func(isset($connection->onWebSocketPing)?$connection->onWebSocketPing:$connection->worker->onWebSocketPing, $connection, $ping_data);
-                            } catch (\Exception $e) {
-                                Worker::stopAll(250, $e);
-                            } catch (\Error $e) {
+                                $ping_cb($connection, $ping_data);
+                            } catch (\Throwable $e) {
                                 Worker::stopAll(250, $e);
                             }
                         } else {
@@ -175,12 +175,11 @@ class Websocket implements \Workerman\Protocols\ProtocolInterface
                         $tmp_connection_type = isset($connection->websocketType) ? $connection->websocketType : static::BINARY_TYPE_BLOB;
                         $connection->websocketType = "\x8a";
                         // Try to emit onWebSocketPong callback.
-                        if (isset($connection->onWebSocketPong) || isset($connection->worker->onWebSocketPong)) {
+                        $pong_cb = $connection->onWebSocketPong ?? $connection->worker->onWebSocketPong ?? false;
+                        if ($pong_cb) {
                             try {
-                                \call_user_func(isset($connection->onWebSocketPong)?$connection->onWebSocketPong:$connection->worker->onWebSocketPong, $connection, $pong_data);
-                            } catch (\Exception $e) {
-                                Worker::stopAll(250, $e);
-                            } catch (\Error $e) {
+                                $pong_cb($connection, $pong_data);
+                            } catch (\Throwable $e) {
                                 Worker::stopAll(250, $e);
                             }
                         }
@@ -207,7 +206,7 @@ class Websocket implements \Workerman\Protocols\ProtocolInterface
         elseif ($connection->websocketCurrentFrameLength < $recv_len) {
             static::decode(\substr($buffer, 0, $connection->websocketCurrentFrameLength), $connection);
             $connection->consumeRecvBuffer($connection->websocketCurrentFrameLength);
-            $current_frame_length                    = $connection->websocketCurrentFrameLength;
+            $current_frame_length = $connection->websocketCurrentFrameLength;
             $connection->websocketCurrentFrameLength = 0;
             // Continue to read next frame.
             return static::input(\substr($buffer, $current_frame_length), $connection);
@@ -220,7 +219,7 @@ class Websocket implements \Workerman\Protocols\ProtocolInterface
     /**
      * Websocket encode.
      *
-     * @param string              $buffer
+     * @param string $buffer
      * @param ConnectionInterface $connection
      * @return string
      */
@@ -255,10 +254,8 @@ class Websocket implements \Workerman\Protocols\ProtocolInterface
             if (\strlen($connection->tmpWebsocketData) > $connection->maxSendBufferSize) {
                 if ($connection->onError) {
                     try {
-                        \call_user_func($connection->onError, $connection, \WORKERMAN_SEND_FAIL, 'send buffer full and drop package');
-                    } catch (\Exception $e) {
-                        Worker::stopAll(250, $e);
-                    } catch (\Error $e) {
+                        ($connection->onError)($connection, ConnectionInterface::SEND_FAIL, 'send buffer full and drop package');
+                    } catch (\Throwable $e) {
                         Worker::stopAll(250, $e);
                     }
                 }
@@ -269,15 +266,12 @@ class Websocket implements \Workerman\Protocols\ProtocolInterface
             if ($connection->maxSendBufferSize <= \strlen($connection->tmpWebsocketData)) {
                 if ($connection->onBufferFull) {
                     try {
-                        \call_user_func($connection->onBufferFull, $connection);
-                    } catch (\Exception $e) {
-                        Worker::stopAll(250, $e);
-                    } catch (\Error $e) {
+                        ($connection->onBufferFull)($connection);
+                    } catch (\Throwable $e) {
                         Worker::stopAll(250, $e);
                     }
                 }
             }
-
             // Return empty string.
             return '';
         }
@@ -288,7 +282,7 @@ class Websocket implements \Workerman\Protocols\ProtocolInterface
     /**
      * Websocket decode.
      *
-     * @param string              $buffer
+     * @param string $buffer
      * @param ConnectionInterface $connection
      * @return string
      */
@@ -297,14 +291,14 @@ class Websocket implements \Workerman\Protocols\ProtocolInterface
         $len = \ord($buffer[1]) & 127;
         if ($len === 126) {
             $masks = \substr($buffer, 4, 4);
-            $data  = \substr($buffer, 8);
+            $data = \substr($buffer, 8);
         } else {
             if ($len === 127) {
                 $masks = \substr($buffer, 10, 4);
-                $data  = \substr($buffer, 14);
+                $data = \substr($buffer, 14);
             } else {
                 $masks = \substr($buffer, 2, 4);
-                $data  = \substr($buffer, 6);
+                $data = \substr($buffer, 6);
             }
         }
         $dataLength = \strlen($data);
@@ -315,7 +309,7 @@ class Websocket implements \Workerman\Protocols\ProtocolInterface
             return $connection->websocketDataBuffer;
         } else {
             if ($connection->websocketDataBuffer !== '') {
-                $decoded                         = $connection->websocketDataBuffer . $decoded;
+                $decoded = $connection->websocketDataBuffer . $decoded;
                 $connection->websocketDataBuffer = '';
             }
             return $decoded;
@@ -325,7 +319,7 @@ class Websocket implements \Workerman\Protocols\ProtocolInterface
     /**
      * Websocket handshake.
      *
-     * @param string                              $buffer
+     * @param string $buffer
      * @param TcpConnection $connection
      * @return int
      */
@@ -345,7 +339,7 @@ class Websocket implements \Workerman\Protocols\ProtocolInterface
             if (\preg_match("/Sec-WebSocket-Key: *(.*?)\r\n/i", $buffer, $match)) {
                 $Sec_WebSocket_Key = $match[1];
             } else {
-                $connection->close("HTTP/1.1 200 WebSocket\r\nServer: workerman/".Worker::VERSION."\r\n\r\n<div style=\"text-align:center\"><h1>WebSocket</h1><hr>workerman/".Worker::VERSION."</div>",
+                $connection->close("HTTP/1.1 200 WebSocket\r\nServer: workerman/" . Worker::VERSION . "\r\n\r\n<div style=\"text-align:center\"><h1>WebSocket</h1><hr>workerman/" . Worker::VERSION . "</div>",
                     true);
                 return 0;
             }
@@ -353,10 +347,10 @@ class Websocket implements \Workerman\Protocols\ProtocolInterface
             $new_key = \base64_encode(\sha1($Sec_WebSocket_Key . "258EAFA5-E914-47DA-95CA-C5AB0DC85B11", true));
             // Handshake response data.
             $handshake_message = "HTTP/1.1 101 Switching Protocols\r\n"
-                                ."Upgrade: websocket\r\n"
-                                ."Sec-WebSocket-Version: 13\r\n"
-                                ."Connection: Upgrade\r\n"
-                                ."Sec-WebSocket-Accept: " . $new_key . "\r\n";
+                . "Upgrade: websocket\r\n"
+                . "Sec-WebSocket-Version: 13\r\n"
+                . "Connection: Upgrade\r\n"
+                . "Sec-WebSocket-Accept: " . $new_key . "\r\n";
 
             // Websocket data buffer.
             $connection->websocketDataBuffer = '';
@@ -375,7 +369,7 @@ class Websocket implements \Workerman\Protocols\ProtocolInterface
             $has_server_header = false;
 
             if (isset($connection->headers)) {
-                if (\is_array($connection->headers))  {
+                if (\is_array($connection->headers)) {
                     foreach ($connection->headers as $header) {
                         if (\strpos($header, 'Server:') === 0) {
                             $has_server_header = true;
@@ -387,7 +381,7 @@ class Websocket implements \Workerman\Protocols\ProtocolInterface
                 }
             }
             if (!$has_server_header) {
-                $handshake_message .= "Server: workerman/".Worker::VERSION."\r\n";
+                $handshake_message .= "Server: workerman/" . Worker::VERSION . "\r\n";
             }
             $handshake_message .= "\r\n";
             // Send handshake response.
@@ -396,21 +390,13 @@ class Websocket implements \Workerman\Protocols\ProtocolInterface
             $connection->websocketHandshake = true;
 
             // Try to emit onWebSocketConnect callback.
-            $on_websocket_connect = isset($connection->onWebSocketConnect) ? $connection->onWebSocketConnect :
-                (isset($connection->worker->onWebSocketConnect) ? $connection->worker->onWebSocketConnect : false);
+            $on_websocket_connect = $connection->onWebSocketConnect ?? $connection->worker->onWebSocketConnect ?? false;
             if ($on_websocket_connect) {
-                static::parseHttpHeader($buffer);
                 try {
-                    \call_user_func($on_websocket_connect, $connection, $buffer);
-                } catch (\Exception $e) {
-                    Worker::stopAll(250, $e);
-                } catch (\Error $e) {
+                    $on_websocket_connect($connection, new Request($buffer));
+                } catch (\Throwable $e) {
                     Worker::stopAll(250, $e);
                 }
-                if (!empty($_SESSION) && \class_exists('\GatewayWorker\Lib\Context')) {
-                    $connection->session = \GatewayWorker\Lib\Context::sessionEncode($_SESSION);
-                }
-                $_GET = $_SERVER = $_SESSION = $_COOKIE = array();
             }
 
             // There are data waiting to be sent.
@@ -430,63 +416,9 @@ class Websocket implements \Workerman\Protocols\ProtocolInterface
             return 0;
         }
         // Bad websocket handshake request.
-        $connection->close("HTTP/1.1 200 WebSocket\r\nServer: workerman/".Worker::VERSION."\r\n\r\n<div style=\"text-align:center\"><h1>WebSocket</h1><hr>workerman/".Worker::VERSION."</div>",
+        $connection->close("HTTP/1.1 200 WebSocket\r\nServer: workerman/" . Worker::VERSION . "\r\n\r\n<div style=\"text-align:center\"><h1>WebSocket</h1><hr>workerman/" . Worker::VERSION . "</div>",
             true);
         return 0;
     }
 
-    /**
-     * Parse http header.
-     *
-     * @param string $buffer
-     * @return void
-     */
-    protected static function parseHttpHeader($buffer)
-    {
-        // Parse headers.
-        list($http_header, ) = \explode("\r\n\r\n", $buffer, 2);
-        $header_data = \explode("\r\n", $http_header);
-
-        if ($_SERVER) {
-            $_SERVER = array();
-        }
-
-        list($_SERVER['REQUEST_METHOD'], $_SERVER['REQUEST_URI'], $_SERVER['SERVER_PROTOCOL']) = \explode(' ',
-            $header_data[0]);
-
-        unset($header_data[0]);
-        foreach ($header_data as $content) {
-            // \r\n\r\n
-            if (empty($content)) {
-                continue;
-            }
-            list($key, $value)       = \explode(':', $content, 2);
-            $key                     = \str_replace('-', '_', \strtoupper($key));
-            $value                   = \trim($value);
-            $_SERVER['HTTP_' . $key] = $value;
-            switch ($key) {
-                // HTTP_HOST
-                case 'HOST':
-                    $tmp                    = \explode(':', $value);
-                    $_SERVER['SERVER_NAME'] = $tmp[0];
-                    if (isset($tmp[1])) {
-                        $_SERVER['SERVER_PORT'] = $tmp[1];
-                    }
-                    break;
-                // cookie
-                case 'COOKIE':
-                    \parse_str(\str_replace('; ', '&', $_SERVER['HTTP_COOKIE']), $_COOKIE);
-                    break;
-            }
-        }
-
-        // QUERY_STRING
-        $_SERVER['QUERY_STRING'] = \parse_url($_SERVER['REQUEST_URI'], \PHP_URL_QUERY);
-        if ($_SERVER['QUERY_STRING']) {
-            // $GET
-            \parse_str($_SERVER['QUERY_STRING'], $_GET);
-        } else {
-            $_SERVER['QUERY_STRING'] = '';
-        }
-    }
 }

+ 52 - 61
Protocols/Ws.php → src/Protocols/Ws.php

@@ -11,10 +11,11 @@
  * @link      http://www.workerman.net/
  * @license   http://www.opensource.org/licenses/mit-license.php MIT License
  */
+
 namespace Workerman\Protocols;
 
 use Workerman\Worker;
-use Workerman\Lib\Timer;
+use Workerman\Timer;
 use Workerman\Connection\TcpConnection;
 use Workerman\Connection\ConnectionInterface;
 
@@ -40,7 +41,7 @@ class Ws
     /**
      * Check the integrity of the package.
      *
-     * @param string              $buffer
+     * @param string $buffer
      * @param ConnectionInterface $connection
      * @return int
      */
@@ -67,11 +68,11 @@ class Ws
             }
         } else {
 
-            $firstbyte    = \ord($buffer[0]);
-            $secondbyte   = \ord($buffer[1]);
-            $data_len     = $secondbyte & 127;
+            $firstbyte = \ord($buffer[0]);
+            $secondbyte = \ord($buffer[1]);
+            $data_len = $secondbyte & 127;
             $is_fin_frame = $firstbyte >> 7;
-            $masked       = $secondbyte >> 7;
+            $masked = $secondbyte >> 7;
 
             if ($masked) {
                 Worker::safeEcho("frame masked so close the connection\n");
@@ -79,7 +80,7 @@ class Ws
                 return 0;
             }
 
-            $opcode       = $firstbyte & 0xf;
+            $opcode = $firstbyte & 0xf;
 
             switch ($opcode) {
                 case 0x0:
@@ -95,10 +96,8 @@ class Ws
                     // Try to emit onWebSocketClose callback.
                     if (isset($connection->onWebSocketClose)) {
                         try {
-                            \call_user_func($connection->onWebSocketClose, $connection);
-                        } catch (\Exception $e) {
-                            Worker::stopAll(250, $e);
-                        } catch (\Error $e) {
+                            ($connection->onWebSocketClose)($connection);
+                        } catch (\Throwable $e) {
                             Worker::stopAll(250, $e);
                         }
                     } // Close connection.
@@ -130,7 +129,7 @@ class Ws
                     return 0;
                 }
                 $arr = \unpack('n/N2c', $buffer);
-                $current_frame_length = $arr['c1']*4294967296 + $arr['c2'] + 10;
+                $current_frame_length = $arr['c1'] * 4294967296 + $arr['c2'] + 10;
             } else {
                 $current_frame_length = $data_len + 2;
             }
@@ -151,10 +150,8 @@ class Ws
                         $connection->websocketType = "\x8a";
                         if (isset($connection->onWebSocketPing)) {
                             try {
-                                \call_user_func($connection->onWebSocketPing, $connection, $ping_data);
-                            } catch (\Exception $e) {
-                                Worker::stopAll(250, $e);
-                            } catch (\Error $e) {
+                                ($connection->onWebSocketPing)($connection, $ping_data);
+                            } catch (\Throwable $e) {
                                 Worker::stopAll(250, $e);
                             }
                         } else {
@@ -176,10 +173,8 @@ class Ws
                         // Try to emit onWebSocketPong callback.
                         if (isset($connection->onWebSocketPong)) {
                             try {
-                                \call_user_func($connection->onWebSocketPong, $connection, $pong_data);
-                            } catch (\Exception $e) {
-                                Worker::stopAll(250, $e);
-                            } catch (\Error $e) {
+                                ($connection->onWebSocketPong)($connection, $pong_data);
+                            } catch (\Throwable $e) {
                                 Worker::stopAll(250, $e);
                             }
                         }
@@ -205,7 +200,7 @@ class Ws
         elseif ($connection->websocketCurrentFrameLength < $recv_len) {
             self::decode(\substr($buffer, 0, $connection->websocketCurrentFrameLength), $connection);
             $connection->consumeRecvBuffer($connection->websocketCurrentFrameLength);
-            $current_frame_length                    = $connection->websocketCurrentFrameLength;
+            $current_frame_length = $connection->websocketCurrentFrameLength;
             $connection->websocketCurrentFrameLength = 0;
             // Continue to read next frame.
             return self::input(\substr($buffer, $current_frame_length), $connection);
@@ -218,7 +213,7 @@ class Ws
     /**
      * Websocket encode.
      *
-     * @param string              $buffer
+     * @param string $buffer
      * @param ConnectionInterface $connection
      * @return string
      */
@@ -237,10 +232,10 @@ class Ws
         $pack = '';
         $length = $length_flag = \strlen($payload);
         if (65535 < $length) {
-            $pack   = \pack('NN', ($length & 0xFFFFFFFF00000000) >> 32, $length & 0x00000000FFFFFFFF);
+            $pack = \pack('NN', ($length & 0xFFFFFFFF00000000) >> 32, $length & 0x00000000FFFFFFFF);
             $length_flag = 127;
         } else if (125 < $length) {
-            $pack   = \pack('n*', $length);
+            $pack = \pack('n*', $length);
             $length_flag = 126;
         }
 
@@ -256,10 +251,8 @@ class Ws
             if (\strlen($connection->tmpWebsocketData) > $connection->maxSendBufferSize) {
                 if ($connection->onError) {
                     try {
-                        \call_user_func($connection->onError, $connection, \WORKERMAN_SEND_FAIL, 'send buffer full and drop package');
-                    } catch (\Exception $e) {
-                        Worker::stopAll(250, $e);
-                    } catch (\Error $e) {
+                        ($connection->onError)($connection, ConnectionInterface::SEND_FAIL, 'send buffer full and drop package');
+                    } catch (\Throwable $e) {
                         Worker::stopAll(250, $e);
                     }
                 }
@@ -270,10 +263,8 @@ class Ws
             if ($connection->maxSendBufferSize <= \strlen($connection->tmpWebsocketData)) {
                 if ($connection->onBufferFull) {
                     try {
-                        \call_user_func($connection->onBufferFull, $connection);
-                    } catch (\Exception $e) {
-                        Worker::stopAll(250, $e);
-                    } catch (\Error $e) {
+                        ($connection->onBufferFull)($connection);
+                    } catch (\Throwable $e) {
                         Worker::stopAll(250, $e);
                     }
                 }
@@ -286,7 +277,7 @@ class Ws
     /**
      * Websocket decode.
      *
-     * @param string              $buffer
+     * @param string $buffer
      * @param ConnectionInterface $connection
      * @return string
      */
@@ -306,7 +297,7 @@ class Ws
             return $connection->websocketDataBuffer;
         } else {
             if ($connection->websocketDataBuffer !== '') {
-                $decoded_data                    = $connection->websocketDataBuffer . $decoded_data;
+                $decoded_data = $connection->websocketDataBuffer . $decoded_data;
                 $connection->websocketDataBuffer = '';
             }
             return $decoded_data;
@@ -330,10 +321,10 @@ class Ws
      */
     public static function onClose($connection)
     {
-        $connection->handshakeStep               = null;
+        $connection->handshakeStep = null;
         $connection->websocketCurrentFrameLength = 0;
-        $connection->tmpWebsocketData            = '';
-        $connection->websocketDataBuffer         = '';
+        $connection->tmpWebsocketData = '';
+        $connection->websocketDataBuffer = '';
         if (!empty($connection->websocketPingTimer)) {
             Timer::del($connection->websocketPingTimer);
             $connection->websocketPingTimer = null;
@@ -360,34 +351,34 @@ class Ws
             (isset($connection->wsHttpHeader) ? $connection->wsHttpHeader : null);
         $user_header_str = '';
         if (!empty($user_header)) {
-            if (\is_array($user_header)){
-                foreach($user_header as $k=>$v){
+            if (\is_array($user_header)) {
+                foreach ($user_header as $k => $v) {
                     $user_header_str .= "$k: $v\r\n";
                 }
             } else {
                 $user_header_str .= $user_header;
             }
-            $user_header_str = "\r\n".\trim($user_header_str);
+            $user_header_str = "\r\n" . \trim($user_header_str);
         }
-        $header = 'GET ' . $connection->getRemoteURI() . " HTTP/1.1\r\n".
-        (!\preg_match("/\nHost:/i", $user_header_str) ? "Host: $host\r\n" : '').
-        "Connection: Upgrade\r\n".
-        "Upgrade: websocket\r\n".
-        (isset($connection->websocketOrigin) ? "Origin: ".$connection->websocketOrigin."\r\n":'').
-        (isset($connection->WSClientProtocol)?"Sec-WebSocket-Protocol: ".$connection->WSClientProtocol."\r\n":'').
-        "Sec-WebSocket-Version: 13\r\n".
-        "Sec-WebSocket-Key: " . $connection->websocketSecKey . $user_header_str . "\r\n\r\n";
+        $header = 'GET ' . $connection->getRemoteURI() . " HTTP/1.1\r\n" .
+            (!\preg_match("/\nHost:/i", $user_header_str) ? "Host: $host\r\n" : '') .
+            "Connection: Upgrade\r\n" .
+            "Upgrade: websocket\r\n" .
+            (isset($connection->websocketOrigin) ? "Origin: " . $connection->websocketOrigin . "\r\n" : '') .
+            (isset($connection->WSClientProtocol) ? "Sec-WebSocket-Protocol: " . $connection->WSClientProtocol . "\r\n" : '') .
+            "Sec-WebSocket-Version: 13\r\n" .
+            "Sec-WebSocket-Key: " . $connection->websocketSecKey . $user_header_str . "\r\n\r\n";
         $connection->send($header, true);
-        $connection->handshakeStep               = 1;
+        $connection->handshakeStep = 1;
         $connection->websocketCurrentFrameLength = 0;
-        $connection->websocketDataBuffer         = '';
-        $connection->tmpWebsocketData            = '';
+        $connection->websocketDataBuffer = '';
+        $connection->tmpWebsocketData = '';
     }
 
     /**
      * Websocket handshake.
      *
-     * @param string                              $buffer
+     * @param string $buffer
      * @param TcpConnection $connection
      * @return int
      */
@@ -420,16 +411,14 @@ class Ws
             // Try to emit onWebSocketConnect callback.
             if (isset($connection->onWebSocketConnect)) {
                 try {
-                    \call_user_func($connection->onWebSocketConnect, $connection, \substr($buffer, 0, $handshake_response_length));
-                } catch (\Exception $e) {
-                    Worker::stopAll(250, $e);
-                } catch (\Error $e) {
+                    ($connection->onWebSocketConnect)($connection, \substr($buffer, 0, $handshake_response_length));
+                } catch (\Throwable $e) {
                     Worker::stopAll(250, $e);
                 }
             }
             // Headbeat.
             if (!empty($connection->websocketPingInterval)) {
-                $connection->websocketPingTimer = Timer::add($connection->websocketPingInterval, function() use ($connection){
+                $connection->websocketPingTimer = Timer::add($connection->websocketPingInterval, function () use ($connection) {
                     if (false === $connection->send(\pack('H*', '898000000000'), true)) {
                         Timer::del($connection->websocketPingTimer);
                         $connection->websocketPingTimer = null;
@@ -449,12 +438,14 @@ class Ws
         return 0;
     }
 
-    public static function WSSetProtocol($connection, $params) {
-	$connection->WSClientProtocol = $params[0];
+    public static function WSSetProtocol($connection, $params)
+    {
+        $connection->WSClientProtocol = $params[0];
     }
 
-    public static function WSGetServerProtocol($connection) {
-	return (\property_exists($connection, 'WSServerProtocol') ? $connection->WSServerProtocol : null);
+    public static function WSGetServerProtocol($connection)
+    {
+        return (\property_exists($connection, 'WSServerProtocol') ? $connection->WSServerProtocol : null);
     }
 
 }

+ 29 - 21
Timer.php → src/Timer.php

@@ -14,14 +14,12 @@
 namespace Workerman;
 
 use Workerman\Events\EventInterface;
+use Workerman\Events\Select;
 use Workerman\Worker;
 use \Exception;
 
 /**
  * Timer.
- *
- * example:
- * Workerman\Timer::add($time_interval, callback, array($arg1, $arg2..));
  */
 class Timer
 {
@@ -35,12 +33,12 @@ class Timer
      *
      * @var array
      */
-    protected static $_tasks = array();
+    protected static $_tasks = [];
 
     /**
      * event
      *
-     * @var EventInterface
+     * @var Select
      */
     protected static $_event = null;
 
@@ -61,7 +59,7 @@ class Timer
      *
      * @var array
      */
-    protected static $_status = array();
+    protected static $_status = [];
 
     /**
      * Init.
@@ -76,7 +74,7 @@ class Timer
             return;
         }
         if (\function_exists('pcntl_signal')) {
-            \pcntl_signal(\SIGALRM, array('\Workerman\Lib\Timer', 'signalHandle'), false);
+            \pcntl_signal(\SIGALRM, ['\Workerman\Timer', 'signalHandle'], false);
         }
     }
 
@@ -102,20 +100,19 @@ class Timer
      * @param bool     $persistent
      * @return int|bool
      */
-    public static function add($time_interval, $func, $args = array(), $persistent = true)
+    public static function add(float $time_interval, $func, $args = [], $persistent = true)
     {
-        if ($time_interval <= 0) {
+        if ($time_interval < 0) {
             Worker::safeEcho(new Exception("bad time_interval"));
             return false;
         }
 
         if ($args === null) {
-            $args = array();
+            $args = [];
         }
 
         if (self::$_event) {
-            return self::$_event->add($time_interval,
-                $persistent ? EventInterface::EV_TIMER : EventInterface::EV_TIMER_ONCE, $func, $args);
+            return $persistent ? self::$_event->repeat($time_interval, $func, $args) : self::$_event->delay($time_interval, $func, $args);
         }
 
         if (!\is_callable($func)) {
@@ -129,16 +126,27 @@ class Timer
 
         $run_time = \time() + $time_interval;
         if (!isset(self::$_tasks[$run_time])) {
-            self::$_tasks[$run_time] = array();
+            self::$_tasks[$run_time] = [];
         }
 
         self::$_timerId = self::$_timerId == \PHP_INT_MAX ? 1 : ++self::$_timerId;
         self::$_status[self::$_timerId] = true;
-        self::$_tasks[$run_time][self::$_timerId] = array($func, (array)$args, $persistent, $time_interval);
+        self::$_tasks[$run_time][self::$_timerId] = [$func, (array)$args, $persistent, $time_interval];
 
         return self::$_timerId;
     }
 
+    /**
+     * @param float $delay
+     * @param $func
+     * @param array $args
+     * @return bool|int
+     */
+    public function delay(float $delay, $func, $args = [])
+    {
+        return $this->add($delay, $func, $args);
+    }
+
 
     /**
      * Tick.
@@ -160,14 +168,14 @@ class Timer
                     $persistent    = $one_task[2];
                     $time_interval = $one_task[3];
                     try {
-                        \call_user_func_array($task_func, $task_args);
-                    } catch (\Exception $e) {
+                        $task_func(...$task_args);
+                    } catch (\Throwable $e) {
                         Worker::safeEcho($e);
                     }
                     if($persistent && !empty(self::$_status[$index])) {
                         $new_run_time = \time() + $time_interval;
-                        if(!isset(self::$_tasks[$new_run_time])) self::$_tasks[$new_run_time] = array();
-                        self::$_tasks[$new_run_time][$index] = array($task_func, (array)$task_args, $persistent, $time_interval);
+                        if(!isset(self::$_tasks[$new_run_time])) self::$_tasks[$new_run_time] = [];
+                        self::$_tasks[$new_run_time][$index] = [$task_func, (array)$task_args, $persistent, $time_interval];
                     }
                 }
                 unset(self::$_tasks[$run_time]);
@@ -184,7 +192,7 @@ class Timer
     public static function del($timer_id)
     {
         if (self::$_event) {
-            return self::$_event->del($timer_id, EventInterface::EV_TIMER);
+            return self::$_event->deleteTimer($timer_id);
         }
 
         foreach(self::$_tasks as $run_time => $task_data) 
@@ -204,10 +212,10 @@ class Timer
      */
     public static function delAll()
     {
-        self::$_tasks = self::$_status = array();
+        self::$_tasks = self::$_status = [];
         \pcntl_alarm(0);
         if (self::$_event) {
-            self::$_event->clearAllTimer();
+            self::$_event->deleteAllTimer();
         }
     }
 }

+ 138 - 224
Worker.php → src/Worker.php

@@ -12,16 +12,16 @@
  * @license   http://www.opensource.org/licenses/mit-license.php MIT License
  */
 namespace Workerman;
-require_once __DIR__ . '/Lib/Constants.php';
 
 use Workerman\Events\EventInterface;
 use Workerman\Connection\ConnectionInterface;
 use Workerman\Connection\TcpConnection;
 use Workerman\Connection\UdpConnection;
-use Workerman\Lib\Timer;
+use Workerman\Timer;
 use Workerman\Events\Select;
 use \Exception;
 
+
 /**
  * Worker class
  * A container for listening ports
@@ -33,7 +33,7 @@ class Worker
      *
      * @var string
      */
-    const VERSION = '4.0.32';
+    const VERSION = '5.0.0';
 
     /**
      * Status starting.
@@ -64,14 +64,6 @@ class Worker
     const STATUS_RELOADING = 8;
 
     /**
-     * After sending the restart command to the child process KILL_WORKER_TIMER_TIME seconds,
-     * if the process is still living then forced to kill.
-     *
-     * @var int
-     */
-    const KILL_WORKER_TIMER_TIME = 2;
-
-    /**
      * Default backlog. Backlog is the maximum length of the queue of pending connections.
      *
      * @var int
@@ -215,7 +207,7 @@ class Worker
      *
      * @var array
      */
-    public $connections = array();
+    public $connections = [];
 
     /**
      * Application layer protocol.
@@ -225,13 +217,6 @@ class Worker
     public $protocol = null;
 
     /**
-     * Root path for autoload.
-     *
-     * @var string
-     */
-    protected $_autoloadRootPath = '';
-
-    /**
      * Pause accept new connections or not.
      *
      * @var bool
@@ -271,7 +256,7 @@ class Worker
      * @var string
      */
     public static $statusFile = '';
-    
+
     /**
      * Log file.
      *
@@ -282,7 +267,7 @@ class Worker
     /**
      * Global event loop.
      *
-     * @var EventInterface
+     * @var Select
      */
     public static $globalEvent = null;
 
@@ -315,6 +300,20 @@ class Worker
     public static $processTitle = 'WorkerMan';
 
     /**
+     * After sending the stop command to the child process stopTimeout seconds,
+     * if the process is still living then forced to kill.
+     *
+     * @var int
+     */
+    public static $stopTimeout = 2;
+
+    /**
+     * Command
+     * @var string
+     */
+    public static $command = '';
+
+    /**
      * The PID of master process.
      *
      * @var int
@@ -354,7 +353,7 @@ class Worker
      *
      * @var Worker[]
      */
-    protected static $_workers = array();
+    protected static $_workers = [];
 
     /**
      * All worker processes pid.
@@ -362,7 +361,7 @@ class Worker
      *
      * @var array
      */
-    protected static $_pidMap = array();
+    protected static $_pidMap = [];
 
     /**
      * All worker processes waiting for restart.
@@ -370,7 +369,7 @@ class Worker
      *
      * @var array
      */
-    protected static $_pidsToRestart = array();
+    protected static $_pidsToRestart = [];
 
     /**
      * Mapping from PID to worker process ID.
@@ -378,7 +377,7 @@ class Worker
      *
      * @var array
      */
-    protected static $_idMap = array();
+    protected static $_idMap = [];
 
     /**
      * Current status.
@@ -444,57 +443,50 @@ class Worker
     protected static $_startFile = '';
 
     /**
-     * OS.
-     *
-     * @var string
-     */
-    protected static $_OS = \OS_TYPE_LINUX;
-
-    /**
      * Processes for windows.
      *
      * @var array
      */
-    protected static $_processForWindows = array();
+    protected static $_processForWindows = [];
 
     /**
      * Status info of current worker process.
      *
      * @var array
      */
-    protected static $_globalStatistics = array(
+    protected static $_globalStatistics = [
         'start_timestamp'  => 0,
-        'worker_exit_info' => array()
-    );
+        'worker_exit_info' => []
+    ];
 
     /**
      * Available event loops.
      *
      * @var array
      */
-    protected static $_availableEventLoops = array(
+    protected static $_availableEventLoops = [
         'event'    => '\Workerman\Events\Event',
         'libevent' => '\Workerman\Events\Libevent'
-    );
+    ];
 
     /**
      * PHP built-in protocols.
      *
      * @var array
      */
-    protected static $_builtinTransports = array(
+    protected static $_builtinTransports = [
         'tcp'   => 'tcp',
         'udp'   => 'udp',
         'unix'  => 'unix',
         'ssl'   => 'tcp'
-    );
+    ];
 
     /**
      * PHP built-in error types.
      *
      * @var array
      */
-    protected static $_errorType = array(
+    protected static $_errorType = [
         \E_ERROR             => 'E_ERROR',             // 1
         \E_WARNING           => 'E_WARNING',           // 2
         \E_PARSE             => 'E_PARSE',             // 4
@@ -510,7 +502,7 @@ class Worker
         \E_RECOVERABLE_ERROR => 'E_RECOVERABLE_ERROR', // 4096
         \E_DEPRECATED        => 'E_DEPRECATED',        // 8192
         \E_USER_DEPRECATED   => 'E_USER_DEPRECATED'   // 16384
-    );
+    ];
 
     /**
      * Graceful stop or not.
@@ -562,9 +554,6 @@ class Worker
         if (\PHP_SAPI !== 'cli') {
             exit("Only run in command line mode \n");
         }
-        if (\DIRECTORY_SEPARATOR === '\\') {
-            self::$_OS = \OS_TYPE_WINDOWS;
-        }
     }
 
     /**
@@ -592,7 +581,7 @@ class Worker
 
         // Log file.
         if (empty(static::$logFile)) {
-            static::$logFile = __DIR__ . '/../workerman.log';
+            static::$logFile = __DIR__ . '/../../workerman.log';
         }
         $log_file = (string)static::$logFile;
         if (!\is_file($log_file)) {
@@ -648,12 +637,10 @@ class Worker
      */
     protected static function initWorkers()
     {
-        if (static::$_OS !== \OS_TYPE_LINUX) {
+        if (\DIRECTORY_SEPARATOR !== '/') {
             return;
         }
-        
-        static::$_statisticsFile =  static::$statusFile ? static::$statusFile : __DIR__ . '/../workerman-' .posix_getpid().'.status';
-
+        static::$_statisticsFile =  static::$statusFile ?: __DIR__ . '/../workerman-' .posix_getpid().'.status';
         foreach (static::$_workers as $worker) {
             // Worker name.
             if (empty($worker->name)) {
@@ -678,7 +665,7 @@ class Worker
             // Get column mapping for UI
             foreach(static::getUiColumns() as $column_name => $prop){
                 !isset($worker->{$prop}) && $worker->{$prop} = 'NNNN';
-                $prop_length = \strlen((string) $worker->{$prop});
+                $prop_length = \strlen($worker->{$prop});
                 $key = '_max' . \ucfirst(\strtolower($column_name)) . 'NameLength';
                 static::$$key = \max(static::$$key, $prop_length);
             }
@@ -716,7 +703,7 @@ class Worker
     /**
      * Get global event-loop instance.
      *
-     * @return EventInterface
+     * @return Select
      */
     public static function getEventLoop()
     {
@@ -738,7 +725,7 @@ class Worker
     protected static function initId()
     {
         foreach (static::$_workers as $worker_id => $worker) {
-            $new_id_map = array();
+            $new_id_map = [];
             $worker->count = $worker->count < 1 ? 1 : $worker->count;
             for($key = 0; $key < $worker->count; $key++) {
                 $new_id_map[$key] = isset(static::$_idMap[$worker_id][$key]) ? static::$_idMap[$worker_id][$key] : 0;
@@ -765,20 +752,20 @@ class Worker
      */
     protected static function displayUI()
     {
-        global $argv;
-        if (\in_array('-q', $argv)) {
+        $tmp_argv = static::getArgv();
+        if (\in_array('-q', $tmp_argv)) {
             return;
         }
-        if (static::$_OS !== \OS_TYPE_LINUX) {
+        if (\DIRECTORY_SEPARATOR !== '/') {
             static::safeEcho("----------------------- WORKERMAN -----------------------------\r\n");
             static::safeEcho('Workerman version:'. static::VERSION. '          PHP version:'. \PHP_VERSION. "\r\n");
             static::safeEcho("------------------------ WORKERS -------------------------------\r\n");
-            static::safeEcho("worker                        listen                              processes status\r\n");
+            static::safeEcho("worker               listen                              processes status\r\n");
             return;
         }
 
         //show version
-        $line_version = 'Workerman version:' . static::VERSION . \str_pad('PHP version:', 22, ' ', \STR_PAD_LEFT) . \PHP_VERSION . \PHP_EOL;
+        $line_version = 'Workerman version:' . static::VERSION . \str_pad('PHP version:', 16, ' ', \STR_PAD_LEFT) . \PHP_VERSION . \str_pad('Event-loop:', 16, ' ', \STR_PAD_LEFT) . static::getEventLoopName() . \PHP_EOL;
         !\defined('LINE_VERSIOIN_LENGTH') && \define('LINE_VERSIOIN_LENGTH', \strlen($line_version));
         $total_length = static::getSingleLineTotalLength();
         $line_one = '<n>' . \str_pad('<w> WORKERMAN </w>', $total_length + \strlen('<w></w>'), '-', \STR_PAD_BOTH) . '</n>'. \PHP_EOL;
@@ -800,9 +787,9 @@ class Worker
             $content = '';
             foreach(static::getUiColumns() as $column_name => $prop){
                 $key = '_max' . \ucfirst(\strtolower($column_name)) . 'NameLength';
-                \preg_match_all("/(<n>|<\/n>|<w>|<\/w>|<g>|<\/g>)/is", (string) $worker->{$prop}, $matches);
+                \preg_match_all("/(<n>|<\/n>|<w>|<\/w>|<g>|<\/g>)/is", $worker->{$prop}, $matches);
                 $place_holder_length = !empty($matches) ? \strlen(\implode('', $matches[0])) : 0;
-                $content .= \str_pad((string) $worker->{$prop}, static::$$key + static::UI_SAFE_LENGTH + $place_holder_length);
+                $content .= \str_pad($worker->{$prop}, static::$$key + static::UI_SAFE_LENGTH + $place_holder_length);
             }
             $content && static::safeEcho($content . \PHP_EOL);
         }
@@ -812,15 +799,9 @@ class Worker
         !empty($content) && static::safeEcho($line_last);
 
         if (static::$daemonize) {
-            $tmpArgv = $argv;
-            foreach ($tmpArgv as $index => $value) {
-                if ($value == '-d') {
-                    unset($tmpArgv[$index]);
-                } elseif ($value == 'start' || $value == 'restart') {
-                    $tmpArgv[$index] = 'stop';
-                }
-            }
-            static::safeEcho("Input \"php ".implode(' ', $tmpArgv)."\" to stop. Start success.\n\n");
+            global $argv;
+            $start_file = $argv[0];
+            static::safeEcho('Input "php '. $start_file . ' stop" to stop. Start success.' . "\n\n");
         } else {
             static::safeEcho("Press Ctrl+C to stop. Start success.\n");
         }
@@ -829,21 +810,21 @@ class Worker
     /**
      * Get UI columns to be shown in terminal
      *
-     * 1. $column_map: array('ui_column_name' => 'clas_property_name')
+     * 1. $column_map: ['ui_column_name' => 'clas_property_name']
      * 2. Consider move into configuration in future
      *
      * @return array
      */
     public static function getUiColumns()
     {
-        return array(
+        return [
             'proto'     =>  'transport',
             'user'      =>  'user',
             'worker'    =>  'name',
             'socket'    =>  'socket',
             'processes' =>  'count',
             'status'    =>  'status',
-        );
+        ];
     }
 
     /**
@@ -874,27 +855,27 @@ class Worker
      */
     protected static function parseCommand()
     {
-        if (static::$_OS !== \OS_TYPE_LINUX) {
+        if (\DIRECTORY_SEPARATOR !== '/') {
             return;
         }
         global $argv;
         // Check argv;
         $start_file = $argv[0];
         $usage = "Usage: php yourfile <command> [mode]\nCommands: \nstart\t\tStart worker in DEBUG mode.\n\t\tUse mode -d to start in DAEMON mode.\nstop\t\tStop worker.\n\t\tUse mode -g to stop gracefully.\nrestart\t\tRestart workers.\n\t\tUse mode -d to start in DAEMON mode.\n\t\tUse mode -g to stop gracefully.\nreload\t\tReload codes.\n\t\tUse mode -g to reload gracefully.\nstatus\t\tGet worker status.\n\t\tUse mode -d to show live status.\nconnections\tGet worker connections.\n";
-        $available_commands = array(
+        $available_commands = [
             'start',
             'stop',
             'restart',
             'reload',
             'status',
             'connections',
-        );
-        $available_mode = array(
+        ];
+        $available_mode = [
             '-d',
             '-g'
-        );
+        ];
         $command = $mode = '';
-        foreach ($argv as $value) {
+        foreach (static::getArgv() as $value) {
             if (\in_array($value, $available_commands)) {
                 $command = $value;
             } elseif (\in_array($value, $available_mode)) {
@@ -930,7 +911,7 @@ class Worker
             exit;
         }
 
-        $statistics_file =  static::$statusFile ? static::$statusFile : __DIR__ . "/../workerman-$master_pid.status";
+        $statistics_file =  static::$statusFile ?: __DIR__ . "/../workerman-$master_pid.status";
 
         // execute command.
         switch ($command) {
@@ -1029,6 +1010,12 @@ class Worker
         }
     }
 
+    public static function getArgv()
+    {
+        global $argv;
+        return isset($argv[1]) ? $argv : (static::$command ? \explode(' ', static::$command) : $argv);
+    }
+
     /**
      * Format status data.
      *
@@ -1037,7 +1024,7 @@ class Worker
      */
     protected static function formatStatusData($statistics_file)
     {
-        static $total_request_cache = array();
+        static $total_request_cache = [];
         if (!\is_readable($statistics_file)) {
             return '';
         }
@@ -1046,11 +1033,11 @@ class Worker
             return '';
         }
         $status_str = '';
-        $current_total_request = array();
+        $current_total_request = [];
         $worker_info = \unserialize($info[0]);
         \ksort($worker_info, SORT_NUMERIC);
         unset($info[0]);
-        $data_waiting_sort = array();
+        $data_waiting_sort = [];
         $read_process_status = false;
         $total_requests = 0;
         $total_qps = 0;
@@ -1120,28 +1107,13 @@ class Worker
      */
     protected static function installSignal()
     {
-        if (static::$_OS !== \OS_TYPE_LINUX) {
+        if (\DIRECTORY_SEPARATOR !== '/') {
             return;
         }
-        $signalHandler = '\Workerman\Worker::signalHandler';
-        // stop
-        \pcntl_signal(\SIGINT, $signalHandler, false);
-        // stop
-        \pcntl_signal(\SIGTERM, $signalHandler, false);
-        // stop
-        \pcntl_signal(\SIGHUP, $signalHandler, false);
-        // stop
-        \pcntl_signal(\SIGTSTP, $signalHandler, false);
-        // graceful stop
-        \pcntl_signal(\SIGQUIT, $signalHandler, false);
-        // reload
-        \pcntl_signal(\SIGUSR1, $signalHandler, false);
-        // graceful reload
-        \pcntl_signal(\SIGUSR2, $signalHandler, false);
-        // status
-        \pcntl_signal(\SIGIOT, $signalHandler, false);
-        // connection status
-        \pcntl_signal(\SIGIO, $signalHandler, false);
+        $signals = [\SIGINT, \SIGTERM, \SIGHUP, \SIGTSTP, \SIGQUIT, \SIGUSR1, \SIGUSR2, \SIGIOT, \SIGIO];
+        foreach ($signals as $signal) {
+            \pcntl_signal($signal, [Worker::class, 'signalHandler'], false);
+        }
         // ignore
         \pcntl_signal(\SIGPIPE, \SIG_IGN, false);
     }
@@ -1153,44 +1125,14 @@ class Worker
      */
     protected static function reinstallSignal()
     {
-        if (static::$_OS !== \OS_TYPE_LINUX) {
+        if (\DIRECTORY_SEPARATOR !== '/') {
             return;
         }
-        $signalHandler = '\Workerman\Worker::signalHandler';
-        // uninstall stop signal handler
-        \pcntl_signal(\SIGINT, \SIG_IGN, false);
-        // uninstall stop signal handler
-        \pcntl_signal(\SIGTERM, \SIG_IGN, false);
-        // uninstall stop signal handler
-        \pcntl_signal(\SIGHUP, \SIG_IGN, false);
-        // uninstall stop signal handler
-        \pcntl_signal(\SIGTSTP, \SIG_IGN, false);
-        // uninstall graceful stop signal handler
-        \pcntl_signal(\SIGQUIT, \SIG_IGN, false);
-        // uninstall reload signal handler
-        \pcntl_signal(\SIGUSR1, \SIG_IGN, false);
-        // uninstall graceful reload signal handler
-        \pcntl_signal(\SIGUSR2, \SIG_IGN, false);
-        // uninstall status signal handler
-        \pcntl_signal(\SIGIOT, \SIG_IGN, false);
-        // uninstall connections status signal handler
-        \pcntl_signal(\SIGIO, \SIG_IGN, false);
-        // reinstall stop signal handler
-        static::$globalEvent->add(\SIGINT, EventInterface::EV_SIGNAL, $signalHandler);
-        // reinstall graceful stop signal handler
-        static::$globalEvent->add(\SIGQUIT, EventInterface::EV_SIGNAL, $signalHandler);
-        // reinstall graceful stop signal handler
-        static::$globalEvent->add(\SIGHUP, EventInterface::EV_SIGNAL, $signalHandler);
-        // reinstall graceful stop signal handler
-        static::$globalEvent->add(\SIGTSTP, EventInterface::EV_SIGNAL, $signalHandler);
-        // reinstall reload signal handler
-        static::$globalEvent->add(\SIGUSR1, EventInterface::EV_SIGNAL, $signalHandler);
-        // reinstall graceful reload signal handler
-        static::$globalEvent->add(\SIGUSR2, EventInterface::EV_SIGNAL, $signalHandler);
-        // reinstall status signal handler
-        static::$globalEvent->add(\SIGIOT, EventInterface::EV_SIGNAL, $signalHandler);
-        // reinstall connection status signal handler
-        static::$globalEvent->add(\SIGIO, EventInterface::EV_SIGNAL, $signalHandler);
+        $signals = [\SIGINT, \SIGTERM, \SIGHUP, \SIGTSTP, \SIGQUIT, \SIGUSR1, \SIGUSR2, \SIGIOT, \SIGIO];
+        foreach ($signals as $signal) {
+            \pcntl_signal($signal, \SIG_IGN, false);
+            static::$globalEvent->onSignal($signal, '\Workerman\Worker::signalHandler');
+        };
     }
 
     /**
@@ -1239,7 +1181,7 @@ class Worker
      */
     protected static function daemonize()
     {
-        if (!static::$daemonize || static::$_OS !== \OS_TYPE_LINUX) {
+        if (!static::$daemonize || \DIRECTORY_SEPARATOR !== '/') {
             return;
         }
         \umask(0);
@@ -1268,7 +1210,7 @@ class Worker
      */
     public static function resetStd()
     {
-        if (!static::$daemonize || static::$_OS !== \OS_TYPE_LINUX) {
+        if (!static::$daemonize || \DIRECTORY_SEPARATOR !== '/') {
             return;
         }
         global $STDOUT, $STDERR;
@@ -1303,7 +1245,7 @@ class Worker
      */
     protected static function saveMasterPid()
     {
-        if (static::$_OS !== \OS_TYPE_LINUX) {
+        if (\DIRECTORY_SEPARATOR !== '/') {
             return;
         }
 
@@ -1351,7 +1293,7 @@ class Worker
      */
     protected static function getAllWorkerPids()
     {
-        $pid_array = array();
+        $pid_array = [];
         foreach (static::$_pidMap as $worker_pid_array) {
             foreach ($worker_pid_array as $worker_pid) {
                 $pid_array[$worker_pid] = $worker_pid;
@@ -1367,7 +1309,7 @@ class Worker
      */
     protected static function forkWorkers()
     {
-        if (static::$_OS === \OS_TYPE_LINUX) {
+        if (\DIRECTORY_SEPARATOR === '/') {
             static::forkWorkersForLinux();
         } else {
             static::forkWorkersForWindows();
@@ -1407,8 +1349,7 @@ class Worker
     protected static function forkWorkersForWindows()
     {
         $files = static::getStartFilesForWindows();
-        global $argv;
-        if(\in_array('-q', $argv) || \count($files) === 1)
+        if(\in_array('-q', static::getArgv()) || \count($files) === 1)
         {
             if(\count(static::$_workers) > 1)
             {
@@ -1425,7 +1366,7 @@ class Worker
             $worker = current(static::$_workers);
 
             // Display UI.
-            static::safeEcho(\str_pad($worker->name, 30) . \str_pad($worker->getSocketName(), 36) . \str_pad($worker->count, 10) . "[ok]\n");
+            static::safeEcho(\str_pad($worker->name, 21) . \str_pad($worker->getSocketName(), 36) . \str_pad($worker->count, 10) . "[ok]\n");
             $worker->listen();
             $worker->run();
             exit("@@@child exit@@@\r\n");
@@ -1447,9 +1388,8 @@ class Worker
      * @return array
      */
     public static function getStartFilesForWindows() {
-        global $argv;
-        $files = array();
-        foreach($argv as $file)
+        $files = [];
+        foreach(static::getArgv() as $file)
         {
             if(\is_file($file))
             {
@@ -1540,7 +1480,7 @@ class Worker
             if (static::$_status === static::STATUS_STARTING) {
                 static::resetStd();
             }
-            static::$_pidMap  = array();
+            static::$_pidMap  = [];
             // Remove other listener.
             foreach(static::$_workers as $key => $one_worker) {
                 if ($one_worker->workerId !== $worker->workerId) {
@@ -1620,13 +1560,7 @@ class Worker
     protected static function setProcessTitle($title)
     {
         \set_error_handler(function(){});
-        // >=php 5.5
-        if (\function_exists('cli_set_process_title')) {
-            \cli_set_process_title($title);
-        } // Need proctitle when php<=5.5 .
-        elseif (\extension_loaded('proctitle') && \function_exists('setproctitle')) {
-            \setproctitle($title);
-        }
+        \cli_set_process_title($title);
         \restore_error_handler();
     }
 
@@ -1637,7 +1571,7 @@ class Worker
      */
     protected static function monitorWorkers()
     {
-        if (static::$_OS === \OS_TYPE_LINUX) {
+        if (\DIRECTORY_SEPARATOR === '/') {
             static::monitorWorkersForLinux();
         } else {
             static::monitorWorkersForWindows();
@@ -1714,7 +1648,7 @@ class Worker
     {
         Timer::add(1, "\\Workerman\\Worker::checkWorkerStatusForWindows");
 
-        static::$globalEvent->loop();
+        static::$globalEvent->run();
     }
 
     /**
@@ -1757,9 +1691,7 @@ class Worker
                 if (static::$onMasterReload) {
                     try {
                         \call_user_func(static::$onMasterReload);
-                    } catch (\Exception $e) {
-                        static::stopAll(250, $e);
-                    } catch (\Error $e) {
+                    } catch (\Throwable $e) {
                         static::stopAll(250, $e);
                     }
                     static::initId();
@@ -1773,7 +1705,7 @@ class Worker
             }
 
             // Send reload signal to all child processes.
-            $reloadable_pid_array = array();
+            $reloadable_pid_array = [];
             foreach (static::$_pidMap as $worker_id => $worker_pid_array) {
                 $worker = static::$_workers[$worker_id];
                 if ($worker->reloadable) {
@@ -1802,9 +1734,9 @@ class Worker
             $one_worker_pid = \current(static::$_pidsToRestart);
             // Send reload signal to a worker process.
             \posix_kill($one_worker_pid, $sig);
-            // If the process does not exit after static::KILL_WORKER_TIMER_TIME seconds try to kill it.
+            // If the process does not exit after stopTimeout seconds try to kill it.
             if(!static::$_gracefulStop){
-                Timer::add(static::KILL_WORKER_TIMER_TIME, '\posix_kill', array($one_worker_pid, \SIGKILL), false);
+                Timer::add(static::$stopTimeout, '\posix_kill', [$one_worker_pid, \SIGKILL], false);
             }
         } // For child processes.
         else {
@@ -1814,9 +1746,7 @@ class Worker
             if ($worker->onWorkerReload) {
                 try {
                     \call_user_func($worker->onWorkerReload, $worker);
-                } catch (\Exception $e) {
-                    static::stopAll(250, $e);
-                } catch (\Error $e) {
+                } catch (\Throwable $e) {
                     static::stopAll(250, $e);
                 }
             }
@@ -1853,7 +1783,7 @@ class Worker
             foreach ($worker_pid_array as $worker_pid) {
                 \posix_kill($worker_pid, $sig);
                 if(!static::$_gracefulStop){
-                    Timer::add(static::KILL_WORKER_TIMER_TIME, '\posix_kill', array($worker_pid, \SIGKILL), false);
+                    Timer::add(static::$stopTimeout, '\posix_kill', [$worker_pid, \SIGKILL], false);
                 }
             }
             Timer::add(1, "\\Workerman\\Worker::checkIfChildRunning");
@@ -1871,9 +1801,9 @@ class Worker
                 }
             }
             if (!static::$_gracefulStop || ConnectionInterface::$statistics['connection_count'] <= 0) {
-                static::$_workers = array();
+                static::$_workers = [];
                 if (static::$globalEvent) {
-                    static::$globalEvent->destroy();
+                    static::$globalEvent->stop();
                 }
 
                 try {
@@ -1928,17 +1858,17 @@ class Worker
     {
         // For master process.
         if (static::$_masterPid === \posix_getpid()) {
-            $all_worker_info = array();
+            $all_worker_info = [];
             foreach(static::$_pidMap as $worker_id => $pid_array) {
                 /** @var /Workerman/Worker $worker */
                 $worker = static::$_workers[$worker_id];
                 foreach($pid_array as $pid) {
-                    $all_worker_info[$pid] = array('name' => $worker->name, 'listen' => $worker->getSocketName());
+                    $all_worker_info[$pid] = ['name' => $worker->name, 'listen' => $worker->getSocketName()];
                 }
             }
 
             \file_put_contents(static::$_statisticsFile, \serialize($all_worker_info)."\n", \FILE_APPEND);
-            $loadavg = \function_exists('sys_getloadavg') ? \array_map('round', \sys_getloadavg(), array(2,2,2)) : array('-', '-', '-');
+            $loadavg = \function_exists('sys_getloadavg') ? \array_map('round', \sys_getloadavg(), [2,2,2]) : ['-', '-', '-'];
             \file_put_contents(static::$_statisticsFile,
                 "----------------------------------------------GLOBAL STATUS----------------------------------------------------\n", \FILE_APPEND);
             \file_put_contents(static::$_statisticsFile,
@@ -2085,7 +2015,7 @@ class Worker
     public static function checkErrors()
     {
         if (static::STATUS_SHUTDOWN !== static::$_status) {
-            $error_msg = static::$_OS === \OS_TYPE_LINUX ? 'Worker['. \posix_getpid() .'] process terminated' : 'Worker process terminated';
+            $error_msg = \DIRECTORY_SEPARATOR === '/' ? 'Worker['. \posix_getpid() .'] process terminated' : 'Worker process terminated';
             $errors    = error_get_last();
             if ($errors && ($errors['type'] === \E_ERROR ||
                     $errors['type'] === \E_PARSE ||
@@ -2127,7 +2057,7 @@ class Worker
             static::safeEcho($msg);
         }
         \file_put_contents((string)static::$logFile, \date('Y-m-d H:i:s') . ' ' . 'pid:'
-            . (static::$_OS === \OS_TYPE_LINUX ? \posix_getpid() : 1) . ' ' . $msg, \FILE_APPEND | \LOCK_EX);
+            . (\DIRECTORY_SEPARATOR === '/' ? \posix_getpid() : 1) . ' ' . $msg, \FILE_APPEND | \LOCK_EX);
     }
 
     /**
@@ -2150,8 +2080,8 @@ class Worker
                 $green = "\033[32;40m";
                 $end = "\033[0m";
             }
-            $msg = \str_replace(array('<n>', '<w>', '<g>'), array($line, $white, $green), $msg);
-            $msg = \str_replace(array('</n>', '</w>', '</g>'), $end, $msg);
+            $msg = \str_replace(['<n>', '<w>', '<g>'], [$line, $white, $green], $msg);
+            $msg = \str_replace(['</n>', '</w>', '</g>'], $end, $msg);
         } elseif (!static::$_outputDecorated) {
             return false;
         }
@@ -2181,7 +2111,7 @@ class Worker
             static::$_outputDecorated = false;
         } else {
             static::$_outputDecorated =
-                static::$_OS === \OS_TYPE_LINUX &&
+                \DIRECTORY_SEPARATOR === '/' &&
                 \function_exists('posix_isatty') &&
                 \posix_isatty($stream);
         }
@@ -2194,17 +2124,12 @@ class Worker
      * @param string $socket_name
      * @param array  $context_option
      */
-    public function __construct($socket_name = '', array $context_option = array())
+    public function __construct($socket_name = '', array $context_option = [])
     {
         // Save all worker instances.
         $this->workerId                    = \spl_object_hash($this);
         static::$_workers[$this->workerId] = $this;
-        static::$_pidMap[$this->workerId]  = array();
-
-        // Get autoload root path.
-        $backtrace               = \debug_backtrace();
-        $this->_autoloadRootPath = \dirname($backtrace[0]['file']);
-        Autoloader::setRootPath($this->_autoloadRootPath);
+        static::$_pidMap[$this->workerId]  = [];
 
         // Context for socket.
         if ($socket_name) {
@@ -2216,7 +2141,7 @@ class Worker
         }
 
         // Turn reusePort on.
-        /*if (static::$_OS === \OS_TYPE_LINUX  // if linux
+        /*if (\DIRECTORY_SEPARATOR === '/'  // if linux
             && \version_compare(\PHP_VERSION,'7.0.0', 'ge') // if php >= 7.0.0
             && \version_compare(php_uname('r'), '3.9', 'ge') // if kernel >=3.9
             && \strtolower(\php_uname('s')) !== 'darwin' // if not Mac OS
@@ -2238,9 +2163,6 @@ class Worker
             return;
         }
 
-        // Autoload.
-        Autoloader::setRootPath($this->_autoloadRootPath);
-
         if (!$this->_mainSocket) {
 
             $local_socket = $this->parseSocketAddress();
@@ -2329,7 +2251,9 @@ class Worker
                 throw new Exception('Bad worker->transport ' . \var_export($this->transport, true));
             }
         } else {
-            $this->transport = $scheme;
+            if ($this->transport === 'tcp') {
+                $this->transport = $scheme;
+            }
         }
         //local socket
         return static::$_builtinTransports[$this->transport] . ":" . $address;
@@ -2343,7 +2267,7 @@ class Worker
     public function pauseAccept()
     {
         if (static::$globalEvent && false === $this->_pauseAccept && $this->_mainSocket) {
-            static::$globalEvent->del($this->_mainSocket, EventInterface::EV_READ);
+            static::$globalEvent->offReadable($this->_mainSocket);
             $this->_pauseAccept = true;
         }
     }
@@ -2358,9 +2282,9 @@ class Worker
         // Register a listener to be notified when server socket is ready to read.
         if (static::$globalEvent && true === $this->_pauseAccept && $this->_mainSocket) {
             if ($this->transport !== 'udp') {
-                static::$globalEvent->add($this->_mainSocket, EventInterface::EV_READ, array($this, 'acceptConnection'));
+                static::$globalEvent->onReadable($this->_mainSocket, [$this, 'acceptTcpConnection']);
             } else {
-                static::$globalEvent->add($this->_mainSocket, EventInterface::EV_READ, array($this, 'acceptUdpConnection'));
+                static::$globalEvent->onReadable($this->_mainSocket, [$this, 'acceptUdpConnection']);
             }
             $this->_pauseAccept = false;
         }
@@ -2387,10 +2311,7 @@ class Worker
         static::$_status = static::STATUS_RUNNING;
 
         // Register shutdown function for checking errors.
-        \register_shutdown_function(array("\\Workerman\\Worker", 'checkErrors'));
-
-        // Set autoload root path.
-        Autoloader::setRootPath($this->_autoloadRootPath);
+        \register_shutdown_function(["\\Workerman\\Worker", 'checkErrors']);
 
         // Create a global event loop.
         if (!static::$globalEvent) {
@@ -2415,12 +2336,8 @@ class Worker
         // Try to emit onWorkerStart callback.
         if ($this->onWorkerStart) {
             try {
-                \call_user_func($this->onWorkerStart, $this);
-            } catch (\Exception $e) {
-                // Avoid rapid infinite loop exit.
-                sleep(1);
-                static::stopAll(250, $e);
-            } catch (\Error $e) {
+                ($this->onWorkerStart)($this);
+            } catch (\Throwable $e) {
                 // Avoid rapid infinite loop exit.
                 sleep(1);
                 static::stopAll(250, $e);
@@ -2428,7 +2345,7 @@ class Worker
         }
 
         // Main loop.
-        static::$globalEvent->loop();
+        static::$globalEvent->run();
     }
 
     /**
@@ -2441,11 +2358,9 @@ class Worker
         // Try to emit onWorkerStop callback.
         if ($this->onWorkerStop) {
             try {
-                \call_user_func($this->onWorkerStop, $this);
-            } catch (\Exception $e) {
-                static::stopAll(250, $e);
-            } catch (\Error $e) {
-                static::stopAll(250, $e);
+                ($this->onWorkerStop)($this);
+            } catch (\Throwable $e) {
+                Worker::log($e);
             }
         }
         // Remove listener for server socket.
@@ -2466,7 +2381,7 @@ class Worker
      * @param resource $socket
      * @return void
      */
-    public function acceptConnection($socket)
+    public function acceptTcpConnection($socket)
     {
         // Accept a connection on server socket.
         \set_error_handler(function(){});
@@ -2493,10 +2408,8 @@ class Worker
         // Try to emit onConnect callback.
         if ($this->onConnect) {
             try {
-                \call_user_func($this->onConnect, $connection);
-            } catch (\Exception $e) {
-                static::stopAll(250, $e);
-            } catch (\Error $e) {
+                ($this->onConnect)($connection);
+            } catch (\Throwable $e) {
                 static::stopAll(250, $e);
             }
         }
@@ -2519,7 +2432,8 @@ class Worker
         // UdpConnection.
         $connection           = new UdpConnection($socket, $remote_address);
         $connection->protocol = $this->protocol;
-        if ($this->onMessage) {
+        $message_cb = $this->onMessage;
+        if ($message_cb) {
             try {
                 if ($this->protocol !== null) {
                     /** @var \Workerman\Protocols\ProtocolInterface $parser */
@@ -2532,24 +2446,24 @@ class Worker
                             $package = \substr($recv_buffer, 0, $len);
                             $recv_buffer = \substr($recv_buffer, $len);
                             $data = $parser::decode($package, $connection);
-                            if ($data === false)
+                            if ($data === false) {
                                 continue;
-                            \call_user_func($this->onMessage, $connection, $data);
+                            }
+                            $message_cb($connection, $data);
                         }
                     } else {
                         $data = $parser::decode($recv_buffer, $connection);
                         // Discard bad packets.
-                        if ($data === false)
+                        if ($data === false) {
                             return true;
-                        \call_user_func($this->onMessage, $connection, $data);
+                        }
+                        $message_cb($connection, $data);
                     }
                 } else {
-                    \call_user_func($this->onMessage, $connection, $recv_buffer);
+                    $message_cb($connection, $recv_buffer);
                 }
                 ++ConnectionInterface::$statistics['total_request'];
-            } catch (\Exception $e) {
-                static::stopAll(250, $e);
-            } catch (\Error $e) {
+            } catch (\Throwable $e) {
                 static::stopAll(250, $e);
             }
         }