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专指程序本身可以处理的异常,一般性的异常。

results matching ""

    No results matching ""