在workerman中出现了notice错误并不会中断程序运行,这是抛出一个无关紧要的提示,这显然与我们的程序设计初衷不符。
例如我们去获取数组中的一个key-value值,当key不存在的时候只是提示一个notice,而我们要把这个弄成一个异常。
研究了一下,set_error_handler方法可以实现我们想要的功能,来看一下代码吧。
在events.php中的代码<?php
/**
* 用于检测业务代码死循环或者长时间阻塞等问题
* 如果发现业务卡死,可以将下面declare打开(去掉//注释),并执行php start.php reload
* 然后观察一段时间workerman.log看是否有process_timeout异常
*/
//declare(ticks=1);
use App\Service\MemberService;
use App\Service\InterviewService;
use \GatewayWorker\Lib\Gateway;
use think\facade\Db;
use \App\Library\MyException;
use \App\Library\Rdb;
define('ping', 1);//ping 心跳 返回1
define('bind', 2);//bind 绑定 返回2
define('interview_admin_bind', 999);//集合室后台管理账户绑定
define('interview_member_join', 1001);//集合室-用户进入集合室
define('interview_member_leave', 1002);//集合室-用户离开集合室
define('interview_change_attribute', 1011);//集合室切换fixed 自由座位 和固定座位
define('interview_seat_order', 1012);//集合室座位排序
define('interview_seat_order_rand', 1013);//集合室座位排序-随机
define('interview_seat_change', 1014);//集合室座位排序-交换
define('interview_member_ban', 1015);//集合室-踢出用户
define('interview_member_voice', 1016);//集合室-用户禁言
define('interview_topic', 1017);//集合室出题
define('interview_voice_order', 1018);//传递麦序
define('interview_update', 1050);//集合室-更新频道属性
define('interview_send_msg', 1051);//集合室发送消息
class Events
{
use \App\Library\Tools;
public static function onWorkerStart()
{
\set_error_handler(function ($type, $msg) {
var_dump($type, $msg);
throw new MyException(400, $msg);
}, E_NOTICE);
Db::setConfig(\App\Config\Config::$db_config);
Rdb::getInstance()->flushAll();
}
public static function onConnect($client_id)
{
}
public static function onMessage($client_id, $message)
{
try {
$message = json_decode($message, true);
if (!is_array($message))
return Gateway::sendToCurrentClient(self::error(400, '参数类型错误'));
if ($message['type'] > 1000 and !isset($_SESSION['member_id'])) {
return Gateway::closeClient($client_id, self::error(400, '未登录'));
}
switch ($message['type']) {
case interview_admin_bind:
InterviewService::admin_bind($client_id, $message);
break;
case interview_voice_order:
InterviewService::voice_order($client_id, $message);
break;
case interview_topic:
InterviewService::topic($client_id, $message);
break;
case interview_member_voice:
InterviewService::member_voice($client_id, $message);
break;
case interview_member_ban:
InterviewService::member_ban($client_id, $message);
break;
case interview_seat_change:
InterviewService::seat_change($client_id, $message);
break;
case interview_seat_order_rand:
InterviewService::seat_order_rand($client_id, $message);
break;
case interview_seat_order:
InterviewService::seat_order($client_id, $message);
break;
case interview_send_msg:
InterviewService::send_msg($client_id, $message);
break;
case interview_change_attribute:
InterviewService::change_attribute($client_id, $message);
break;
case interview_update:
InterviewService::update($client_id, $message);
break;
case interview_member_leave:
InterviewService::leave($client_id);
break;
case interview_member_join:
InterviewService::join($client_id, $_SESSION['member_id'], $_SESSION['member'], $message);
break;
case bind:
MemberService::bind($client_id, $message);
break;
default :
return Gateway::sendToCurrentClient(self::success(1));
break;
}
} catch (Throwable $exception) {
if ($exception instanceof MyException) {
return Gateway::sendToCurrentClient(self::error($exception->type, $exception->getMessage(), $exception->getCode(), $exception->data));
} else {
return Gateway::sendToCurrentClient(self::error(400, $exception->getMessage()));
}
}
}
public static function onClose($client_id)
{
InterviewService::leave($client_id);
}
}
Events.php文件主要看onMessage回调,我们通过传递给服务器的不同type参数作为路由凭据,然后调用不同的方法,处理业务。
在最外层有一个try catch来捕捉异常。注意是捕捉的Throwable 。这是Exception和Error两个不同异常的父类接口,但是并不包含notice和warning这类的错误,所以不能捕获。
所以一旦出现了这类错误并不会中断掉程序,那么要来判断例如key-value是否存在的这类情况就太痛苦了,到处都是isset。。。
public static function onWorkerStart()
{
\set_error_handler(function ($type, $msg) {
var_dump($type, $msg);
throw new MyException(400, $msg);
}, E_NOTICE);
Db::setConfig(\App\Config\Config::$db_config);
Rdb::getInstance()->flushAll();
}
在来分析一下onWorkerStart()方法中,我们用set_error_handler来设置E_NOTICE类型的错误交给一个闭包来处理,该闭包抛出一个MyExcepetion异常,这个异常就是继承了Throwable接口,是可以被正常捕获的。同时中断程序。