1. PHP开发
PHP函数开发遇到的问题,有时候是隐藏的,根本不报exception
如下代码,$res
完全是不存在的变量,它只会引发如下错误
$dbres = $pdodb->select("zone",["m5d","state","stato","expire"],["m5d"=>$zone_id]);
if($res == null){
$error = 1;
$reason = "ZoneNotFound:".$zone_id;
$result = ["zone_id"=>$zone_id];
$debug = [];
return ["error"=>1,"reason"=>$reason,"result"=>$result,"debug"=>$debug];
}
Service Unavailable:http invoke error,FC response body format error.outputDefinition is null.outPutBody=false
引发这个错误的原因
- 代码里有了print,导致这些字符串,网关解释不了
- 有些对象,像debug_backtrace生成的是对象,无法json_encode,表现出来,就是网关输出这样的错误。
#### 这个错误原因其实是php里,使用未定义变量$res
的时候,不会报Error而是报notice,因为php语法允许这样的使用。所以try catch 不到这样的错误。
参考PHP 完善的 Error / Exception 的捕获与处理
2. 如何把这样的错误变成exception,并能让代码察觉到呢。在FC里
下面是典型的函数计算里把PHP Notice: Undefined variable
转换成try catch能捕捉到的过程
<?php
error_reporting(E_ALL ^ E_NOTICE);
/*
if you open the initializer feature, please implement the initializer function, as below:
function initializer($context) {
$logger = $GLOBALS['fcLogger'];
$logger->info('initializing');
}
*/
set_error_handler(function ($error_no, $error_msg, $error_file, $error_line) {
switch ($error_no) {
case E_WARNING:
// x / 0 错误 PHP7 依然不能很友好的自动捕获 只会产生 E_WARNING 级的错误
// 捕获判断后 throw new DivisionByZeroError($error_msg)
// 或者使用 intdiv(x, 0) 方法 会自动抛出 DivisionByZeroError 的错误
if (strcmp('Division by zero', $error_msg) == 0) {
throw new \DivisionByZeroError($error_msg);
}
$level_tips = 'PHP Warning: ';
break;
case E_NOTICE:
$level_tips = 'PHP Notice: ';
break;
case E_DEPRECATED:
$level_tips = 'PHP Deprecated: ';
break;
case E_USER_ERROR:
$level_tips = 'User Error: ';
break;
case E_USER_WARNING:
$level_tips = 'User Warning: ';
break;
case E_USER_NOTICE:
$level_tips = 'User Notice: ';
break;
case E_USER_DEPRECATED:
$level_tips = 'User Deprecated: ';
break;
case E_STRICT:
$level_tips = 'PHP Strict: ';
break;
default:
$level_tips = 'Unkonw Type Error: ';
break;
}
// do some handle
$error = $level_tips . $error_msg . ' in ' . $error_file . ' on ' . $error_line;
echo $error . PHP_EOL;
// or throw a ErrorException back to try ... catch block
throw new ErrorException($error);
// 如果 return false 则错误会继续递交给 PHP 标准错误处理
// return false;
}, E_ALL | E_STRICT);
function handler($event, $context) {
$logger = $GLOBALS['fcLogger'];
$logger->info('hello world');
try{
$tmp2 = "a";
if($tmp == 0){
print($tmp2);
}
}catch(Exception $e){
return $e->getMessage();
print($e);
}
return 'hello world';
}
这样的函数计算输出结果是
Response
PHP Notice: Undefined variable: tmp in /code/index.php on 65
Function Logs
FC Invoke Start RequestId: df395516-28e4-41cb-a1c5-8714d18314b4
2020-02-21T11:28:07Z df395516-28e4-41cb-a1c5-8714d18314b4 [INFO] hello world
PHP Notice: Undefined variable: tmp in /code/index.php on 65
FC Invoke End RequestId: df395516-28e4-41cb-a1c5-8714d18314b4
Duration: 7.15 ms, Billed Duration: 100 ms, Memory Size: 512 MB, Max Memory Used: 9.74 MB
'Service Unavailable:http invoke error,fc return={"errorMessage":"Undefined variable: logdata","errorType":"ErrorException","stackTrace":{"file":"\\/code\\/index.php","line":996,"traceString":""}}',
问题:只能监测代码所在文件的错误。
3. 在PHP开发中发现的一个问题
error_reporting(E_ALL);
require 'set_error_handler.php';
/**
* 这里logdata如果赋值NULL,不会引发例外,
* 如果logdata是[],就会引发例外。所以,在代码中尽量保证用[]而不是NULL
**/
$logdata = NULL;
try{
$apid = $logdata["hello"];
print("reach here");
}catch(Exception $e){
print($e->getMessage());
}
print("\nreach out");
输出
reach here
reach out
4. 千万不要在函数计算中写print,会导致函数FC返回503,而且无法查找原因
Service Unavailable:http invoke error,fc return={"errorMessage":"Undefined variable: logdata","errorType":"ErrorException","stackTrace":{"file":"\\/code\\/index.php","line":1085,"traceString":""}}
5. debug_backtrace的返回结果
代码
error_reporting(E_ALL);
$logdata = NULL;
try{
$trace_str = json_encode(debug_backtrace());
if($trace_str == NULL){
print("serialize fail1");
}else if($trace_str == ""){
print("serialize fail2");
}else if($trace_str == "[]"){
print("serialize fail3");
}else{
print($trace_str);
}
}catch(Exception $e){
print($e->getMessage());
}
``
#### 输出
```bash
serialize fail3
下面这种错误例外捕捉不到
Service Unavailable:http invoke error,fc return={"errorMessage":"Undefined class constant 'Unsetable_Zones'","errorType":"Error","stackTrace":{"file":"\/code\/handler_zone.php","line":707,"traceString":""}}
原因是在try内部,调用了一个不存在的常量变量。
5.1. PHP7的异常捕捉
因为PHP7实现了throwable接口,那么就可以使用第一个这种方式来捕获异常。又因为部分Error实现了接口,并且更多的Error变为可捕获的Exception,那么就可以使用第二种方式来捕获异常。下面是在网上找的PHP7的异常层次树: Throwable Exception 异常 ... Error 错误 ArithmeticError 算数错误 DivisionByZeroError 除数为0的错误 AssertionError 声明错误 ParseError 解析错误 TypeError 类型错误
现在写PHP必须考虑版本情况,上面的写法在PHP7中大部分都能实现,但是也会有不同点,在PHP7更新中有一条:更多的Error变为可捕获的Exception,现在的PHP7实现了一个全局的throwable接口,原来老的Exception和其中一部分Error实现了这个接口(interface),PHP7中更多的Error变为可捕获的Exception返回给捕捉器,这样其实和前面提到的扩展try-catch影响范围一样,但是如果不捕获则还是按照Error对待,看下面两个:
https://www.cnblogs.com/Renyi-Fan/p/10739452.html#_label0_1
我猜测它模仿了java的方法 https://blog.csdn.net/u012373281/article/details/90690361 throwable和exception的区别:
1、throwable是父类,exception是子类。
2、throwable是根基,exception是从throwable派生出来的。
3、throwable中包括exception(异常)和error(错误)。
4、throwable用来定义所有可以作为异常被抛出来的类,exception专指程序本身可以处理的异常,一般性的异常。