/** * 初始化一些环境变量 * * @return void */ public static function init() { // 如果没设置$pidFile,则生成默认值 if (empty(self::$pidFile)) { $backtrace = debug_backtrace(); self::$_startFile = $backtrace[count($backtrace) - 1]['file']; self::$pidFile = sys_get_temp_dir() . "/workerman." . str_replace('/', '_', self::$_startFile) . ".pid"; } // 没有设置日志文件,则生成一个默认值 if (empty(self::$logFile)) { self::$logFile = __DIR__ . '/../server.log'; } // 标记状态为启动中 self::$_status = self::STATUS_STARTING; // 启动时间戳 self::$_globalStatistics['start_timestamp'] = time(); Base::getLog()->debug(__METHOD__ . ' worker start timestamp', ['time' => self::$_globalStatistics['start_timestamp']]); // 设置status文件位置 self::$statusFile = sys_get_temp_dir() . '/workerman.status'; Base::getLog()->debug(__METHOD__ . ' set status file', ['file' => self::$statusFile]); // 尝试设置进程名称(需要php>=5.5或者安装了proctitle扩展) self::setProcessTitle('WorkerMan: master process start_file=' . self::$_startFile); // 初始化ID self::initId(); // 初始化定时器 Timer::init(); }
/** * 设置消息回调 * @return void */ public function onMessage($connection, $data) { // 删除定时器 Timer::del($connection->timeout_timerid); $data = json_decode($data, true); $event = $data['event']; // 开始验证 switch ($event) { // 是geteway连接 case 'gateway_connect': if (empty($data['address'])) { echo "address not found\n"; return $connection->close(); } $this->_gatewayConnections[$connection->id] = $data['address']; $this->broadcastAddresses(); break; // 是worker连接 // 是worker连接 case 'worker_connect': $this->_workerConnections[$connection->id] = $connection; $this->broadcastAddresses($connection); break; case 'ping': break; default: echo "unknown event {$event}\n"; $connection->close(); } }
public static function clearTimer() { if (self::$_reconnectTimer) { Timer::del(self::$_reconnectTimer); self::$_reconnectTimer = null; } }
public function scheduleRespawn($delay) { Timer::add($delay / 1000, function ($self) { if ($self->respawnCallback) { call_user_func($self->respawnCallback); } }, array($this), false); }
/** * 当进程启动时一些初始化工作 * @return void */ protected function onWorkerStart() { Timer::add(1, array($this, 'checkGatewayConnections')); $this->checkGatewayConnections(); \GatewayWorker\Lib\Gateway::setBusinessWorker($this); if ($this->_onWorkerStart) { call_user_func($this->_onWorkerStart, $this); } }
/** * 牌局玩家进度广播 */ public static function doApi($player, $data, &$re, $client_id) { $uid = $player->uid; $table = TableDao::getTable($player->tableId); if (!$table) { return 1; } if (!Timer::isExistTimer($table->blinkTimeOut)) { Gateway::bindUid($client_id, $uid); $table->blinkTimeOut = Timer::add(Constants::TABLE_INIT_CHECK_TIME, array($table, 'checkTime')); TableDao::addTable($table->tableId, $table); } if (!isset($table->playerStatus[$uid])) { $table->addUid($uid); GameDao::addInGamePlayer($uid); TableDao::addTable($table->tableId, $table); } if ($data['st'] == 1) { if (!in_array($uid, $table->readyUids)) { $table->readyUids[] = $uid; TableDao::addTable($table->tableId, $table); } if (count($table->readyUids) >= 3) { $table->recordTime = time(); TableDao::addTable($table->tableId, $table); $re['uid'] = -1; Gateway::sendToUid($table->uids, json_encode($re)); } } if ($data['addVal'] != -1) { $uids = $table->uids; $re['uid'] = $uid; foreach ($uids as $_uid) { if ($_uid == $uid) { continue; } $re['addVal'] = $data['addVal']; $re['oldVal'] = $data['oldVal']; Gateway::sendToUid($_uid, json_encode($re)); } } return 1; }
/** * Display a listing of the resource. * * @return Response */ public function index() { require_once '/vendor/workerman/workerman/Autoloader.php'; $http_worker = new Worker("websocket://0.0.0.0:2345"); $http_worker->count = 4; $http_worker->onConnect = function ($connection) { $connection->send('id' . $connection->id); }; $http_worker->onWorkerStart = function ($worker) { // 定时,每10秒一次 \Workerman\Lib\Timer::add(2, function () use($worker) { // 遍历当前进程所有的客户端连接,发送当前服务器的时间 foreach ($worker->connections as $connection) { $connection->send(time()); } }); }; $http_worker->onMessage = function ($connection, $data) { $connection->send('hello world' . $data); }; worker::runAll(); }
public function initRoaming($mob) { Timer::add(0.5, array($this, 'initRoamingCallback')); }
/** * 当与Gateway的连接断开时触发 * @param TcpConnection $connection * @return void */ public function onGatewayClose($connection) { $addr = $connection->remoteAddress; unset($this->gatewayConnections[$addr], $this->_connectingGatewayAddresses[$addr]); if (isset($this->_gatewayAddresses[$addr]) && !isset($this->_waitingConnectGatewayAddresses[$addr])) { Timer::add(1, array($this, 'tryToConnectGateway'), array($addr), false); $this->_waitingConnectGatewayAddresses[$addr] = $addr; } }
public function onRegisterConnectionClose() { Timer::add(1, array($this, 'registerAddress'), null, false); }
<?php use Workerman\Worker; use Workerman\Lib\Timer; // composer autoload include __DIR__ . '/../vendor/autoload.php'; $channel_server = new Channel\Server(); $worker = new Worker(); $worker->onWorkerStart = function () { Channel\Client::on('test event', function ($event_data) { echo 'test event triggered event_data :'; var_dump($event_data); }); Timer::add(5, function () { Channel\Client::publish('test event', 'some data'); }); }; Worker::runAll();
\Workerman\Lib\Timer::add(0.5, function () use($consumer) { if (extension_loaded('sysvmsg')) { // 循环取数据 while (1) { $desiredmsgtype = 1; $msgtype = 0; $message = ''; $maxsize = 65535; // 从队列中获取消息 @see http://php.net/manual/zh/function.msg-receive.php @msg_receive($consumer->queue, $desiredmsgtype, $msgtype, $maxsize, $message, true, MSG_IPC_NOWAIT); if (!$message) { return; } // 假设消息数据为json,格式类似{"class":"class_name", "method":"method_name", "args":[]} $message = json_decode($message, true); // 格式如果是正确的,则尝试执行对应的类方法 if (isset($message['class']) && isset($message['method']) && isset($message['args'])) { // 要调用的类名,加上Consumer命名空间 $class_name = "\\Consumer\\" . $message['class']; // 要调用的方法名 $method = $message['method']; // 调用参数,是个数组 $args = (array) $message['args']; // 类存在则尝试执行 if (class_exists($class_name)) { $class = new $class_name(); $callback = array($class, $method); if (is_callable($callback)) { call_user_func_array($callback, $args); } else { echo "{$class_name}::{$method} not exist\n"; } } else { echo "{$class_name} not exist\n"; } } else { echo "unknow message\n"; } } } });
/** * 当Gateway启动的时候触发的回调函数 * @return void */ public function onWorkerStart() { // 分配一个内部通讯端口 $this->lanPort = function_exists('posix_getppid') ? $this->startPort - posix_getppid() + posix_getpid() : $this->startPort; if ($this->lanPort < 0 || $this->lanPort >= 65535) { $this->lanPort = rand($this->startPort, 65535); } // 如果有设置心跳,则定时执行 if ($this->pingInterval > 0) { $timer_interval = $this->pingNotResponseLimit > 0 ? $this->pingInterval / 2 : $this->pingInterval; Timer::add($timer_interval, array($this, 'ping')); } if (!class_exists('\\Protocols\\GatewayProtocol')) { class_alias('\\GatewayWorker\\Protocols\\GatewayProtocol', 'Protocols\\GatewayProtocol'); } // 初始化gateway内部的监听,用于监听worker的连接已经连接上发来的数据 $this->_innerTcpWorker = new Worker("GatewayProtocol://{$this->lanIp}:{$this->lanPort}"); $this->_innerTcpWorker->listen(); $this->_innerUdpWorker = new Worker("GatewayProtocol://{$this->lanIp}:{$this->lanPort}"); $this->_innerUdpWorker->transport = 'udp'; $this->_innerUdpWorker->listen(); // 重新设置自动加载根目录 Autoloader::setRootPath($this->_appInitPath); // 设置内部监听的相关回调 $this->_innerTcpWorker->onMessage = array($this, 'onWorkerMessage'); $this->_innerUdpWorker->onMessage = array($this, 'onWorkerMessage'); $this->_innerTcpWorker->onConnect = array($this, 'onWorkerConnect'); $this->_innerTcpWorker->onClose = array($this, 'onWorkerClose'); // 注册gateway的内部通讯地址,worker去连这个地址,以便gateway与worker之间建立起TCP长连接 if (!$this->registerAddress()) { $this->log('registerAddress fail and exit'); Worker::stopAll(); } if ($this->_onWorkerStart) { call_user_func($this->_onWorkerStart, $this); } }
$connection->close(); } // onWebSocketConnect 里面$_GET $_SERVER是可用的 // var_dump($_GET, $_SERVER); }; }; */ $webserver = new WebServer('http://0.0.0.0:80'); $webserver->addRoot('120.25.163.9', '/workerman/Applications/huicheng/Web'); $webserver->count = 1; $webserver->onWorkerStart = function ($webserver) { //初始化多客服工号对应的昵称 redisData::Set('HCS1@hc-information', '小汇'); redisData::Set('HCS2@hc-information', '小承'); redisData::Set('HCT1@hc-information', '小信'); redisData::Set('HCT2@hc-information', '小息'); //初始化定时间隔 $time_interval = 7000; //初始化access_token transToWxServer::getaccess_token(); transToWxServer::getjsapi_ticket(); //定时获取access_token \Workerman\Lib\Timer::add($time_interval, function () { transToWxServer::getaccess_token(); transToWxServer::getjsapi_ticket(); }); }; // 如果不是在根目录启动,则运行runAll方法 if (!defined('GLOBAL_START')) { Worker::runAll(); }
/** * Run worker instance. * @return void */ public function run() { //Update process state. self::$_status = self::STATUS_RUNNING; // Eegister shutdown function for checking errors. register_shutdown_function(array("\\Workerman\\Worker", 'checkErrors')); // Set autoload root path. Autoloader::setRootPath($this->_autoloadRootPath); // Create a global event loop. if (!self::$globalEvent) { $eventLoopClass = "\\Workerman\\Events\\" . ucfirst(self::getEventLoopName()); self::$globalEvent = new $eventLoopClass(); // Register a listener to be notified when server socket is ready to read. if ($this->_socketName) { if ($this->transport !== 'udp') { self::$globalEvent->add($this->_mainSocket, EventInterface::EV_READ, array($this, 'acceptConnection')); } else { self::$globalEvent->add($this->_mainSocket, EventInterface::EV_READ, array($this, 'acceptUdpConnection')); } } } // Reinstall signal. self::reinstallSignal(); // Init Timer. Timer::init(self::$globalEvent); // Try to emit onWorkerStart callback. if ($this->onWorkerStart) { try { call_user_func($this->onWorkerStart, $this); } catch (\Exception $e) { echo $e; exit(250); } } // Main loop. self::$globalEvent->loop(); }
<?php use Workerman\Worker; use Workerman\Lib\Timer; // composer autoload include __DIR__ . '/../vendor/autoload.php'; $channel_server = new Channel\Server(); $worker = new Worker(); $worker->onWorkerStart = function () { Channel\Client::$onMessage = function ($channel, $data) { var_dump($channel, $data); }; Channel\Client::subscribe('abc'); Timer::add(5, function () { Channel\Client::publish('abc', array('efg')); }); }; Worker::runAll();
/** * 当用户断开连接时触发 * @param int $client_id * @return void */ public static function onClose($client_id) { \Workerman\Lib\Timer::del(self::$redisConnection->get($client_id)); self::$redisConnection->del($client_id); // 更新MYSQL数据库 self::$connectHC->query("UPDATE `HC` SET `clientid` = 0, `lastouttime` = CURRENT_TIMESTAMP() WHERE clientid='{$client_id}'"); }
public function returnToSpawningPosition($waitDuration) { $delay = $waitDuration ? $waitDuration : 4000; $this->clearTarget(); $this->returnTimeout = Timer::add($delay / 1000, array($this, 'timeoutCallback'), array(), false); }
$sender_io->to($to)->emit('new_msg', @$_POST['content']); // 否则向所有uid推送数据 } else { $sender_io->emit('new_msg', @$_POST['content']); } // http接口返回ok return $http_connection->send('ok'); } return $http_connection->send('fail'); }; // 执行监听 $inner_http_worker->listen(); // 一个定时器,定时向所有uid推送当前uid在线数及在线页面数 Timer::add(1, function () { global $uidConnectionMap, $sender_io, $last_online_count, $last_online_page_count; $online_count_now = count($uidConnectionMap); $online_page_count_now = array_sum($uidConnectionMap); // 只有在客户端在线数变化了才广播,减少不必要的客户端通讯 if ($last_online_count != $online_count_now || $last_online_page_count != $online_page_count_now) { $sender_io->emit('update_online_count', "当前<b>{$online_count_now}</b>人在线,共打开<b>{$online_page_count_now}</b>个页面"); $last_online_count = $online_count_now; $last_online_page_count = $online_page_count_now; } }); }); // 启动一个webserver,用于吐html css js,方便展示 // 这个webserver服务不是必须的,可以将这些html css js文件放到你的项目下用nginx或者apache跑 $web = new WebServer('http://0.0.0.0:2123'); $web->addRoot('localhost', __DIR__ . '/web'); // 运行所有的服务 Worker::runAll();
/** * Websocket handshake. * * @param string $buffer * @param \Workerman\Connection\TcpConnection $connection * @return int */ public static function dealHandshake($buffer, $connection) { $pos = strpos($buffer, "\r\n\r\n"); if ($pos) { // handshake complete $connection->handshakeStep = 2; $handshake_response_length = $pos + 4; // 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::log($e); exit(250); } catch (\Error $e) { Worker::log($e); exit(250); } } // Headbeat. if (!empty($connection->websocketPingInterval)) { $connection->websocketPingTimer = Timer::add($connection->websocketPingInterval, function () use($connection) { if (false === $connection->send(pack('H*', '8900'), true)) { Timer::del($connection->websocketPingTimer); $connection->websocketPingTimer = null; } }); } $connection->consumeRecvBuffer($handshake_response_length); if (!empty($connection->tmpWebsocketData)) { $connection->send($connection->tmpWebsocketData, true); $connection->tmpWebsocketData = ''; } if (strlen($buffer) > $handshake_response_length) { return self::input(substr($buffer, $handshake_response_length), $connection); } } return 0; }
/** * 初始化 * 统计目录检查 * 初始化任务 * @see Man\Core.SocketWorker::onStart() */ protected function onStart() { // 初始化目录 umask(0); $statistic_dir = Config::$dataPath . $this->statisticDir; if (!is_dir($statistic_dir)) { mkdir($statistic_dir, 0777, true); } $log_dir = Config::$dataPath . $this->logDir; if (!is_dir($log_dir)) { mkdir($log_dir, 0777, true); } // 定时保存统计数据 Timer::add(self::WRITE_PERIOD_LENGTH, array($this, 'writeStatisticsToDisk')); Timer::add(self::WRITE_PERIOD_LENGTH, array($this, 'writeLogToDisk')); // 定时清理不用的统计数据 Timer::add(self::CLEAR_PERIOD_LENGTH, array($this, 'clearDisk'), array(Config::$dataPath . $this->statisticDir, self::EXPIRED_TIME)); Timer::add(self::CLEAR_PERIOD_LENGTH, array($this, 'clearDisk'), array(Config::$dataPath . $this->logDir, self::EXPIRED_TIME)); }
public function onClose($reason = '', $description = null) { if ('closed' !== $this->readyState) { Timer::del($this->pingTimeoutTimer); Timer::del($this->checkIntervalTimer); $this->checkIntervalTimer = null; Timer::del($this->upgradeTimeoutTimer); // clean writeBuffer in next tick, so developers can still // grab the writeBuffer on 'close' event $this->writeBuffer = array(); $this->packetsFn = array(); $this->sentCallbackFn = array(); $this->clearTransport(); $this->readyState = 'closed'; $this->emit('close', $this->id, $reason, $description); $this->server = null; $this->request = null; $this->upgradeTransport = null; $this->removeAllListeners(); if (!empty($this->transport)) { $this->transport->removeAllListeners(); $this->transport = null; } } }
/** * 运行worker实例 */ public function run() { // 注册进程退出回调,用来检查是否有错误 register_shutdown_function(array("\\Workerman\\Worker", 'checkErrors')); // 设置自动加载根目录 Autoloader::setRootPath($this->_appInitPath); // 如果没有全局事件轮询,则创建一个 if (!self::$globalEvent) { if (extension_loaded('libevent')) { self::$globalEvent = new Libevent(); } else { self::$globalEvent = new Select(); } // 监听_mainSocket上的可读事件(客户端连接事件) if ($this->_socketName) { if ($this->transport !== 'udp') { self::$globalEvent->add($this->_mainSocket, EventInterface::EV_READ, array($this, 'acceptConnection')); } else { self::$globalEvent->add($this->_mainSocket, EventInterface::EV_READ, array($this, 'acceptUdpConnection')); } } } // 重新安装事件处理函数,使用全局事件轮询监听信号事件 self::reinstallSignal(); // 用全局事件轮询初始化定时器 Timer::init(self::$globalEvent); // 如果有设置进程启动回调,则执行 if ($this->onWorkerStart) { call_user_func($this->onWorkerStart, $this); } // 子进程主循环 self::$globalEvent->loop(); }
case 'heartbeat': // 评测端信息更新 heartbeat($connection, $data); break; case 'update_state': // 评测中更新状态 update_state($connection, $data); break; case 'update': // 评测完更新结果 update($connection, $data); break; case 'login': // 评测端登录 login($connection, $data); break; default: p("Unknown Action ( cid = {$connection->cid}, IP = {$connection->IP} )"); } }; $worker_tasker->onClose = function ($connection) { global $cid, $ava_client, $client_sorted; if ($connection->deadline) { Timer::del($connection->deadline); } if (isset($cid[$connection->cid])) { unset($cid[$connection->cid]); $client_sorted = False; } p("A client closed the connection. ( cid = {$connection->cid}, IP = {$connection->IP} )"); };
if (isset($_REQUEST['sendTo']) && !empty($_REQUEST['sendTo'])) { $SendTo = $_REQUEST['sendTo']; } $SendContent = json_encode(array("data" => htmlspecialchars($_REQUEST['sendContent']))); if (!empty($SendTo)) { $senderIO->to($SendTo)->emit('new_msg_receive', $SendContent); } else { $senderIO->emit('new_msg_receive', $SendContent); } // return status return $httpConnection->send(json_encode(array("result" => true))); } return $httpConnection->send(json_encode(array("result" => false))); }; // Start listening $innerHttpWorker->listen(); // Init a timer Timer::add(1, function () { global $uidConnectionMap, $senderIO, $lastOnlineCount, $lastOnlinePageCount; $onlineCountNow = count($uidConnectionMap); $onlinePageCountNow = array_sum($uidConnectionMap); // Send updated data when client counts changes if ($lastOnlineCount != $onlineCountNow || $lastOnlinePageCount != $onlinePageCountNow) { $senderIO->emit("update_online_user_counts", json_encode(array("data" => $onlineCountNow))); $lastOnlineCount = $onlineCountNow; $lastOnlinePageCount = $onlinePageCountNow; } }); }); // Start service Worker::runAll();
/** * 运行worker实例 */ public function run() { //更新 Worker 状态 self::$_status = self::STATUS_RUNNING; // 注册进程退出回调,用来检查是否有错误 register_shutdown_function(array("\\Workerman\\Worker", 'checkErrors')); // 设置自动加载根目录 Autoloader::setRootPath($this->_appInitPath); // 如果没有全局事件轮询,则创建一个 if (!self::$globalEvent) { $eventLoopClass = "\\Workerman\\Events\\" . ucfirst(self::getEventLoopName()); self::$globalEvent = new $eventLoopClass(); // 监听_mainSocket上的可读事件(客户端连接事件) if ($this->_socketName) { if ($this->transport !== 'udp') { self::$globalEvent->add($this->_mainSocket, EventInterface::EV_READ, array($this, 'acceptConnection')); } else { self::$globalEvent->add($this->_mainSocket, EventInterface::EV_READ, array($this, 'acceptUdpConnection')); } } } // 重新安装事件处理函数,使用全局事件轮询监听信号事件 self::reinstallSignal(); // 用全局事件轮询初始化定时器 Timer::init(self::$globalEvent); // 如果有设置进程启动回调,则执行 if ($this->onWorkerStart) { try { call_user_func($this->onWorkerStart, $this); } catch (\Exception $e) { echo $e; exit(250); } } // 子进程主循环 self::$globalEvent->loop(); }
/** * 当进程启动时一些初始化工作 * @return void */ protected function onWorkerStart() { if (!class_exists('\\Protocols\\GatewayProtocol')) { class_alias('\\GatewayWorker\\Protocols\\GatewayProtocol', 'Protocols\\GatewayProtocol'); } Timer::add(1, array($this, 'checkGatewayConnections')); $this->checkGatewayConnections(); \GatewayWorker\Lib\Gateway::setBusinessWorker($this); if ($this->_onWorkerStart) { call_user_func($this->_onWorkerStart, $this); } }
public function run($mapFilePath) { $self = $this; $this->map = new Map($mapFilePath); $this->map->ready(function () use($self) { $self->initZoneGroups(); $self->map->generateCollisionGrid(); // Populate all mob "roaming" areas foreach ($self->map->mobAreas as $a) { $area = new MobArea($a->id, $a->nb, $a->type, $a->x, $a->y, $a->width, $a->height, $self); $area->spawnMobs(); // @todo bind //$area->onEmpty($self->handleEmptyMobArea->bind($self, area)); $area->onEmpty(function () use($self, $area) { call_user_func(array($self, 'handleEmptyMobArea'), $area); }); $self->mobAreas[] = $area; } // Create all chest areas foreach ($self->map->chestAreas as $a) { $area = new ChestArea($a->id, $a->x, $a->y, $a->w, $a->h, $a->tx, $a->ty, $a->i, $self); $self->chestAreas[] = $area; // @todo bind $area->onEmpty(function () use($self, $area) { call_user_func(array($self, 'handleEmptyChestArea'), $area); }); } // Spawn static chests foreach ($self->map->staticChests as $chest) { $c = $self->createChest($chest->x, $chest->y, $chest->i); $self->addStaticItem($c); } // Spawn static entities $self->spawnStaticEntities(); // Set maximum number of entities contained in each chest area foreach ($self->chestAreas as $area) { $area->setNumberOfEntities(count($area->entities)); } }); $this->map->initMap(); $regenCount = $this->ups * 2; $updateCount = 0; Timer::add(1 / $this->ups, function () use($self, $regenCount, &$updateCount) { $self->processGroups(); $self->processQueues(); if ($updateCount < $regenCount) { $updateCount += 1; } else { if ($self->regenCallback) { call_user_func($self->regenCallback); } $updateCount = 0; } }); echo $this->id . " created capacity: " . $this->maxPlayers . " players \n"; }
/** * 运行worker实例 */ public function run() { // 设置自动加载根目录 Autoloader::setRootPath($this->_appInitPath); // 则创建一个全局事件轮询 if (extension_loaded('libevent')) { self::$globalEvent = new Libevent(); } else { self::$globalEvent = new Select(); } // 监听_mainSocket上的可读事件(客户端连接事件) if ($this->_socketName) { if ($this->transport !== 'udp') { self::$globalEvent->add($this->_mainSocket, EventInterface::EV_READ, array($this, 'acceptConnection')); } else { self::$globalEvent->add($this->_mainSocket, EventInterface::EV_READ, array($this, 'acceptUdpConnection')); } } // 用全局事件轮询初始化定时器 Timer::init(self::$globalEvent); // 如果有设置进程启动回调,则执行 if ($this->onWorkerStart) { call_user_func($this->onWorkerStart, $this); } // 子进程主循环 self::$globalEvent->loop(); }
use Workerman\Lib\Timer; // 默认监控Workerman的Applications目录 $monitor_dir = realpath(__DIR__ . '/..'); // worker $worker = new Worker(); // 名称,方便status时候辨别 $worker->name = 'FileMonitor'; // 该进程收到reload信号不执行reload $worker->reloadable = false; // 进程启动后安装定时器 $worker->onWorkerStart = function () { global $monitor_dir; // 只在debug模式下监控文件,守护进程模式不监控 if (!Worker::$daemonize) { // 定时检查被监控目录文件1秒内是否有修改 Timer::add(1, 'check_files_change', array($monitor_dir)); } }; // 检查文件1秒内是否有修改 function check_files_change($monitor_dir) { // 递归遍历目录 $dir_iterator = new RecursiveDirectoryIterator($monitor_dir); $iterator = new RecursiveIteratorIterator($dir_iterator); $time_now = time(); foreach ($iterator as $file) { // 只监控php文件 if (pathinfo($file, PATHINFO_EXTENSION) != 'php') { continue; } // 在最近1秒内有修改