在正式学习Swoole之前,我们需要先了解Swoole中是如何捕捉异常错误的,否则我们没办法进行错误调试,因为在之前的文章中我们已经说过,Swoole中是不允许直接exit/die
的。
1、可捕获的异常 / 错误
在 PHP 大致有三种类型的可捕获的异常 / 错误
Error:PHP 内核抛出错误的专用类型,如类不存在,函数不存在,函数参数错误,都会抛出此类型的错误,PHP 代码中不应该使用 Error类来作为异常抛出
Exception:应用开发者应该使用的异常基类
ErrorException:此异常基类专门负责将 PHP 的 Warning/Notice 等信息通过 set_error_handler 转换成异常,PHP 未来的规划必然是将所有的 Warning/Notice 转为异常,以便于 PHP 程序能够更好更可控地处理各种错误
以上所有类都实现了
Throwable
接口,也就是说,通过try {} catch(Throwable $e) {}
即可捕获所有可抛出的异常 / 错误
try {
test();
} catch(Throwable $e) {
var_dump($e);
}
示例2:
try {
test();
}
catch (Error $e) {
var_dump($e);
}
catch(Exception $e) {
var_dump($e);
}
2、不可捕获的致命错误和异常
PHP 错误的一个重要级别,如异常 / 错误未捕获时、内存不足时或是一些编译期错误 (继承的类不存在),将会以
E_ERROR
级别抛出一个Fatal Error
,是在程序发生不可回溯的错误时才会触发的,PHP 程序无法捕获这样级别的一种错误,只能通过register_shutdown_function
在后续进行一些处理操作。
3、在协程中捕获运行时异常 / 错误
在 Swoole4
协程编程中,某个协程的代码中抛出错误,会导致整个进程退出,进程所有协程终止执行。
在协程顶层空间可以先进行一次 try/catch
捕获异常 / 错误,仅终止出错的协程。
Co\run(function () {
go(function () {
try {
call_user_func($func);
}
catch (Error $e) {
var_dump($e);
}
catch(Exception $e) {
var_dump($e);
}
});
//协程1的错误不影响协程2
go(function () {
Co::sleep(5);
echo 2;
});
});
4、捕获 Server 运行期致命错误
Server
运行期一旦发生致命错误,那客户端连接将无法得到回应。
如 Web
服务器,如果有致命错误应当向客户端发送 Http 500
错误信息。
在 PHP 中可以通过 register_shutdown_function
+ error_get_last
2 个函数来捕获致命错误,并将错误信息发送给客户端连接。
具体代码示例如下:
$http = new Swoole\Http\Server("127.0.0.1", 9501);
$http->on('request', function ($request, $response) {
register_shutdown_function(function () use ($response) {
$error = error_get_last();
var_dump($error);
switch ($error['type'] ?? null) {
case E_ERROR :
case E_PARSE :
case E_CORE_ERROR :
case E_COMPILE_ERROR :
// log or send:
// error_log($message);
// $server->send($fd, $error['message']);
$response->status(500);
$response->end($error['message']);
break;
}
});
exit(0);
});
$http->start();
5、错误码
在Swoole中,组件调用失败,正常是不会抛出异常的,所以我们可以通过Swoole内置的swoole_last_error()
函数捕捉到错误码。
可使用 swoole_last_error()
获取当前的错误码;
可使用 swoole_strerror(int $errno, 9);
将 Swoole 底层错误码转换成文字错误信息;
例如:
echo swoole_strerror(swoole_last_error(), 9) . PHP_EOL;
echo swoole_strerror(SWOOLE_ERROR_MALLOC_FAIL, 9) . PHP_EOL;
示例2:
swoole_timer_tick($msec, function($timer_id){
$result = $process->write($message);
if($result === false){
$errno = swoole_last_error();//获取最近一次Swoole底层的错误码
$errmsg = swoole_strerror($errno, 9);//将错误码转化为错误信息
echo "[error] errno {$errno} errmsg:{$errmsg}".PHP_EOL;
}else{
echo "[write] success {$result} bytes".PHP_EOL;
}
});
官方的错误码太多了,还包含了Linux的错误码,具体可以参考官方文档:https://wiki.swoole.com/#/other/errno