函數計算PHP Runtime - exception 處理

在本文中,我們來細化講講函數計算中 php runtime 中的異常處理問題,在官方文檔中 php runtime 錯誤處理 沒有講解函數計算php runtime 環境中對於具體的錯誤類型是怎麼處理的?比如級別很低的notice或者warning, 先來看幾個例子:

example

Warning

<?php
function handler($event, $context) {
  $a = 1/0;
  return "ok";
}

執行結果:

{
   "errorMessage": "Division by zero",
   "errorType": "ErrorException",
   "stackTrace": {
      "file": "/code/index.php",
      "line": 3,
      "traceString": ""
   }
} 

NOTICE

<?php
function handler($event, $context) {
  $a = ["a" => 1, "b" => 2];
  $b = $a["c"];
  return "ok";
}

執行結果:

 {
   "errorMessage": "Undefined index: c",
   "errorType": "ErrorException",
   "stackTrace": {
      "file": "/code/index.php",
      "line": 11,
      "traceString": ""
   }
} 

從上面兩個例子我們可以看出,函數計算的 php runtime 對代碼檢查十分嚴格,不管什麼級別的ERROR_TYPE, 都是按照異常來處理,但是有些使用有些php庫的時候,可能會有一些warning或者notice,這個時候會導致在函數計算的環境中不能使用這種php 庫,比如aliyun-openapi-php-sdk

比如下面的代碼:

<?php

require_once __DIR__ . '/aliyun-openapi-php-sdk/aliyun-php-sdk-core/Config.php';
use imm\Request\V20170906 as Imm;

define('PREVIEWURL', 'https://preview.imm.aliyun.com/index.html');

function handler($event, $context) {
    $accessKeyId     = $context["credentials"]["accessKeyId"];
    $accessKeySecret = $context["credentials"]["accessKeySecret"];
    $securityToken   = $context["credentials"]["securityToken"];
    $region          = $context['region'];

    $iClientProfile = DefaultProfile::getProfile(
        $region,
        $accessKeyId,
        $accessKeySecret,
        $securityToken
    );

    $client         = new DefaultAcsClient($iClientProfile);
    $PREVIEWTGTPATH = 'fc-demo-preview-output-php';
    $immProject     = "imm-demo";
    $srcUri         = "oss://fc-imm-demo/test-data/office/test.pptx";

    $bucket   = "fc-imm-demo";
    $fileName = "test.pptx";
    $tgtUri   = sprintf("oss://%s/%s/%s", $bucket, $PREVIEWTGTPATH, $fileName);

    $request = new Imm\CreateOfficeConversionTaskRequest();
    $request->setProject($immProject);
    $request->setSrcUri($srcUri);
    $request->setTgtType("vector");
    $request->setTgtUri($tgtUri);
    $response = $client->getAcsResponse($request);
    print_r($response);
}

執行就會收到這個錯誤, 上面 example 中的 NOTICE 轉變爲exception:

 {
   "errorMessage": "Undefined index: cn-hangzhou#imm",
   "errorType": "ErrorException",
   "stackTrace": {
      "file": "/code/aliyun-openapi-php-sdk/aliyun-php-sdk-core/Regions/LocationService.php",
      "line": 58,
      "traceString": ""
   }
} 

php runtime 中自定義error_handler

當遇見上面所述對的問題時,我們如何規避這種問題呢?答案是使用set_error_handler 來定義自己的處理方法,從而屏蔽runtime中嚴格處理, 對於 Warning 和 Notice 這種級別等錯誤, 詳情可以參考:http://www.php.net/manual/zh/function.set-error-handler.php

對於上面這種問題,我們修改代碼如下:

<?php

require_once __DIR__ . '/aliyun-openapi-php-sdk/aliyun-php-sdk-core/Config.php';
use imm\Request\V20170906 as Imm;

define('PREVIEWURL', 'https://preview.imm.aliyun.com/index.html');

function myErrorHandler($errno, $errstr, $errfile, $errline) {
    if (!(error_reporting() & $errno)) {
        return false;
    }

    switch ($errno) {
    case E_USER_ERROR:
        $errInfo = array(
            "errorMessage" => $errstr,
            "errorType"    => \ServerlessFC\friendly_error_type($errno),
            "stackTrace"   => array(
                "file" => $errfile,
                "line" => $errline,
            ),
        );
        throw new \ErrorException($errstr, 0, $errno, $errfile, $errline);
        break;

    default: // E_USER_WARNING | E_USER_NOTICE
        break;
    }

    /* Don't execute PHP internal error handler */
    return true;
}

// set to the user defined error handler
set_error_handler("myErrorHandler");

function handler($event, $context) {
    $accessKeyId     = $context["credentials"]["accessKeyId"];
    $accessKeySecret = $context["credentials"]["accessKeySecret"];
    $securityToken   = $context["credentials"]["securityToken"];
    $region          = $context['region'];

    $iClientProfile = DefaultProfile::getProfile(
        $region,
        $accessKeyId,
        $accessKeySecret,
        $securityToken
    );

    $client         = new DefaultAcsClient($iClientProfile);
    $PREVIEWTGTPATH = 'fc-demo-preview-output-php';
    $immProject     = "imm-demo";
    $srcUri         = "oss://fc-imm-demo/test-data/office/test.pptx";

    $bucket   = "fc-imm-demo";
    $fileName = "test.pptx";
    $tgtUri   = sprintf("oss://%s/%s/%s", $bucket, $PREVIEWTGTPATH, $fileName);

    $request = new Imm\CreateOfficeConversionTaskRequest();
    $request->setProject($immProject);
    $request->setSrcUri($srcUri);
    $request->setTgtType("vector");
    $request->setTgtUri($tgtUri);
    $response = $client->getAcsResponse($request);
    print_r($response);
}

總結

本文中,詳細解析了函數計算 php runtime 中對於異常的處理, 在php runtime 中,嚴格規範代碼,我們期望加強檢查以便減少用戶編寫diamante犯錯的可能,但是針對一些第三方庫的引入使用可能因爲warning或者notice而無法使用時,函數計算允許用戶通過自定義的set_error_handler來覆蓋runtime中默認處理。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章